Jahed Ahmed

Weekly Report: 21st October 2019

Improving FrontierNav's Tests

This week was mostly around improving FrontierNav's tests which I wrote about separately since it's quite long. You can read about it here.

Sandboxing

I started using Flatpak (via Flathub) for most of the applications I use. I don't know why sandboxing hasn't become the default by now but it's nice to see some progress on it.

Deno also comes to mind as a replacement for Node.js/NPM. It doesn't sandbox, but at least it restricts access. Though, I'm not entirely sure if its reliance on grabbing remote dependencies via HTTPS is safe without lockfiles and hashes. I took a quick look just now and it looks like it's being figured out.

Thanks for reading.

Weekly Report: 14th October 2019

FrontierNav Windows

FrontierNav now supports windows. Not Windows, that's already supported. That is, you can now open up links in pop-out windows to keep them persistent between page navigations. This avoids needing to constantly click and around and go back and forth between pages.

I'm still working out the user experience on smaller screens, but it's not a priority given mobile apps tend to be geared towards a single window experience.

The worst part about this feature is getting the naming right. "Window" is such a generic term and it's used everywhere. I just settled with "AppWindow", though that doesn't help when naming variables. Calling everything appWindow so that it doesn't clash with the window global seems a bit too verbose.

Windows in FrontierNav

Writing my own Router

I finally decided to replace the deprecated redux-little-router dependency I had. I knew it was a relatively simple replacement so I kept putting it off. I even forked it to fix a few issues as it started to go through bit rot. When I did sit down to replace it, I realised a few things.

The idea behind a router for web apps does not need to be tied to the limitations of a URL. A router is really just state and the URL is a representation of that state. So I separated those two out.

Instead of having the URL be updated as part of the router's state, the URL update is just another observer to that state. This allowed me to easily decouple the web-specific details, that is using the History API to persist the route, from the state itself which the rest of the app can use.

Since I have a few years worth of existing code using the URL to decide what to show, this decoupling is still a work in progress. I still have a lot of hardcoded strings linking different pages and routes of the app.

Freedom from Dependencies

Writing my own router is what pushed me to finally implement multiple windows. I'm now able to have multiple routers in the state for each window which greatly simplifies the logic around creating and navigating windows.

Currently, only one router is persisted in the URL, but nothing's really stopping me from persisting all of them. User experience wise, there's still clearly a "main" window, while the others are more ephemeral, so persisting them in the URL doesn't make much sense. Persisting them in local or remote storage might be more useful.

Anyways, if there's one thing I learnt from this, it's to not let your dependencies, libaries and frameworks narrow your thinking. If it prevents you from doing something, it's time to let go of it. You'll save a lot more time than working around it, which will only couple you to it even more.

Typesafe Routing

I implemented an API for type-safe routing to go with my router. The main goal was to remove the hard coded strings used to link pages.

1
2
3
4
5
6
7
8
9
10
11
// Route
"/explore/:gameId/entities/:entityId"

// Path using a hardcoded string
"/explore/astral-chain/entities/enemy-123"

// Path using a Type-safe API and strings for IDs
root().explore('astral-chain').entity('enemy-123').build()

// Path using a Type-safe API and typed objects with IDs
root().explore(game).entity(entity).build()

This has a number of advantages:

I haven't rolled this out yet as I'm still not 100% on how I want to structure the new router state.

Once all of this is complete, I'll have a new open source library to release.

FrontierNav Data Tables

The spreadsheet-like data tables are gradually becoming more and more feature rich. The tables now support sorting by column, importing pre-formatted CSVs, moving entities and various other quality of life improvements. No doubt it will keep getting better as I import more game data.

Hiding Behind Cloudflare

Most of my public infrastructure is now behind Cloudflare. This should reduce the amount of maintenance I need to do in regards to legacy domains (like jahed.io) and security.

I've disabled HTTP access to my servers entirely and HTTP connections as well as legacy domains redirect using Cloudflare's Page Rules. No server needed.

While this does tie me more to Cloudflare, I am already reliant on it for reducing bandwidth costs so from an end user perspective, nothing's really changed. Moving traffic back to my server is a matter of removing SSL Client verification and adding the redirects.

Other Stuff

Thanks for reading.

Weekly Report: 7th October 2019

FrontierNav Terminology

Over the years FrontierNav's data model has changed a lot. This meant various parts of the codebase and web app used a range of words to describe the same thing. As I start introducing more terminology to the public, there's really no room for confusion. So I went through the project, migrated all the data and reduced the number of terms.

As an example, most data models have terms where these mean the same thing:

FrontierNav probably used at least 4 of these terms in the same contexts but now it only uses two: Entity and Relationships.

FrontierNav Performance

It's really hard for me to tell how well FrontierNav performs on lower-end devices as I don't own one. So as a general rule, after finishing a substantial feature, I'll put in some time to improve its performance or at least look into it.

This week, I optimised the Data Tables which uses artificial viewport scrolling to avoid rendering thousands of rows at once. Any lag in rendering is easily noticable while scrolling, even on high-end devices so it's important to optimise it as much as possible. In the React world, that usually means caching function calls (memoizing) and reducing re-renders in general. There's not much else to say about it. React's DevTools are good enough as they provide rendering times and let you know what triggered it to understand where the costs comes from.

Other Stuff

Thanks for reading.

Weekly Report: 22nd July 2019

Desktop UIs

This week I've been doing a lot of UI experiments. A lot of it was fueled by yet another poor desktop experience being introduced by a major web company. This time it was Twitter. Luckily they have Tweetdeck which provides a much better desktop interface anyway.

FrontierNav

FrontierNav Editor Initial Release

The FrontierNav editor is pretty much complete. Of course, there's a lot of features and improvements I'll be adding a long the way as with any product. But in terms of data-entry, the foundations have all been laid.

The biggest issue now I guess is figuring out the best ways for users to apply their changes. FrontierNav isn't active enough to allow any public change to get applied without moderation. So chances are, I'll go for a request-based approach. Users can make changes and send them over for approval when they're done using the import/export feature.

As a first step, I'll be using the editor to fill in the missing data for Xenoblade 2 and X. Adding functionality to the editor as I need it for others to use in the future. That's a much better approach than hacking scripts together and throwing them away.

Automated Change Submissions

I'll probably remove the need to import/export changes in the near future. If changes are stored on Firebase, there's no need for it outside of offline usage. However there's a risk of flooding the database so it'll need to be restricted to trusted "Editors" or rate-limited.

Video Games

I finished "Donkey Kong Country: Tropical Freeze" on the Switch finally. It's a good game. Astounding music and level design. Some flaws. Very different from Mario's more nimble and acrobatic platforming. Donkey Kong's a lot more weighted and slow; as you'd expect from a gorilla.

I'll probably pick up "Starlink: Battle for Atlas" from my backlog next. Not expecting much from it.

Thanks for reading

Weekly Report: 15th July 2019

FrontierNav

Agility

Misc.

Weekly Report: 8th July 2019

I wrote this entire blog post and it was really long, so I broke it down into separate posts. This is just a summary.

FrontierNav

Linux

I spent a lot of time sorting out my workstation. It's a bit long and boring so I wrote a separate blog post on it.

Thanks for reading.

Weekly Report: 1st July 2019

Weekly Report is going to be a new series of blog posts giving an update of what I did in the current week. The aim is to share what I've done and also to help me appreciate and compare my acheivements.

While there will be FrontierNav-related updates in this series. They'll also contain unrelated updates related to my other projects. If you just want FrontierNav updates, you can wait for the monthly FrontierNav Progress Reports.

Read more