Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions _posts/2024-01-22-switching-from-nvm-to-volta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: 'Switching from NVM to Volta'
author: Janusz Lavrnja-Czapski
categories:
- Development
tags:
- javascript
- node
- tooling
- performance
---

### The problem
Developers using WSL as their established environment have no issue switching between Node versions using `nvm`, whereas this operation requires admin rights for Windows users running outside of WSL.

Obtaining admin rights can be a bit of a slow process and is much too slow for something as simple as switching Node versions. Could Volta provide a cross-platform solution that is more straightforward to manage comapared to `nvm`?

### Why switch?

- Faster than NVM.
- Runs using a shim instead of symlinks so doesn't require admin rights for Windows users.
- Can manage Node dependencies in `package.json` instead of having to have a dedicated `.nvmrc` file.
- Automatically switches Node versions when `cd`'ing between projects, functionality that required a custom script with `nvm`.

### How to switch

Run these commands in your root directory:

`rm -rf ~/.nvm`
`rm -rf ~/.npm`
`rm -rf ~/.bower`

Remove `source ~/.nvm` from your `.bashrc` or `.zshrc`, along with any other references to `nvm`.

**Volta installation**

For Mac/Unix systems, run `curl https://get.volta.sh | bash` or for Windows run `winget install Volta.Volta`. More detailed information can be found in the [documentation](https://docs.volta.sh/guide/getting-started).

To globally install a LTS Node version, run `volta install node` in your root directory, or to install a specific version, run like so `volta install node@22.5.1`.

**Pinning dependencies**

If you want to manage a specific Node version within a project, `cd` into your project folder and run `volta pin node@20.16` at the root level of the project, replacing the version number with your own.

```
"volta": {
"node": "20.16.0"
}
```

You'll see that this will create the above entry in your `package.json` which can then be commited to source control. When any other developers with Volta installed pull down this repository and access it via the command line, it will automatically switch their Node version to the one specified.

**Testing the auto-switch**

Now `cd` into another project and run `volta pin node@<new-version-number>`.

Run `node -v` and see the new version number listed. Now `cd` back into your other project with a pinned Node version in the `package.json` and run `node -v` again.

You should see the version number updated automatically without any custom script or configuration!

### Moving forward

Volta seems like a great tool to manage Node versions in a more consistent way across teams with different development environments, less manual intervention and nice fancy features included out-of-the-box.
94 changes: 94 additions & 0 deletions _posts/2024-02-22-refactoring-webgis-map-components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
title: 'Refactoring web GIS map components'
author: Janusz Lavrnja-Czapski
categories:
- Development
tags:
- javascript
- typescript
- best practices
- web gis
---

### The problem:

In the context of the [VENTURA Virtual Decision Room](https://www.bgs.ac.uk/news/bgs-collaborates-on-new-1-million-epsrc-funded-digital-research-project-to-help-make-urban-growth-more-sustainable/), we have recently received the go-ahead to create an open-source version of the project, which will be hosted on GitHub and open to future collaboration from the wider scientific/development community. This has prompted us to consider how we can get the codebase into a state where it is well-documented, organized, and ready for contributions.

Across other BGS projects where we work with Leaflet/ESRI web maps, we have found ourselves in a situation where the component that initializes the map ends up containing large amounts of functionality and quickly becomes bloated. Since the web map is generated via library code, the approach to building applications centered around the map differs architecturally from a standard component-based application, as we can’t utilize HTML templates for display logic. This leads to the creation of elements and interaction with them being implemented with TypeScript/JavaScript methods.

The aim of this refactor is to untangle all the operations in our map.component.ts file.

### The approach:

- Identify common functionalities.

- Extract each of these functionalities into dedicated services.

- Create a singleton service for passing data between components and services.

- Identify areas where complexity can be reduced or better managed.

Within the VENTURA VDR, the main operations being performed are: creating labels, generating HTML pop-ups, interacting with the map, creating layers, and visualizing layers. Below is an indication of the structure we created to organize the functionality:

`label-data.service.ts`

`label-presentation.service.ts`

`data.service.ts`

`interaction.service.ts`

`layer.service.ts`

`map.service.ts`

`popup.service.ts`

`visualization.service.ts`

Once these services were created, we split the functionality from the existing map component into each of the dedicated files. One particularly noteworthy service is the data.service.ts file. It was created as a singleton service so that it could be used across the whole application and not restricted to one particular module.

Inside, it contains a series of getters and setters for data variables that need to be shared between services and components.

```typescript
public get map(): L.Map {
return this.leafletMapObj;
}

public set map(map: L.Map) {
this.leafletMapObj = map;
}

public get timePeriod(): ResultTimePeriod {
return this.activeTimePeriod;
}

public set timePeriod(activeTimePeriod: ResultTimePeriod) {
this.activeTimePeriod = activeTimePeriod;
}

public get scenario(): AllScenarios {
return this.activeScenario;
}

public set scenario(activeScenario: AllScenarios) {
this.activeScenario = activeScenario;
}
```

It can then be called in the following manner:

```typescript
this.dataService.scenario = scenarioData;

this.processSomeData(this.dataService.scenario);
```

Creating this structure allowed us to slim down our map.component.ts file from over 1000 lines to just over 250. Having a well-defined separation of concerns makes it easy for new developers to the project to clearly understand the operations being carried out and allows for simple integration of new functionality.

### Takeaways:

Moving forward, we believe there will be significant value in considering a services-based architecture for our Angular applications that implement a web GIS. This will enable us to build solutions that are well-organized from the start and can scale as the project complexity and lifespan increase.

Further reading can be found [here.](https://medium.com/@snehalv.2010/angular-service-architecture-9e907c96be04).