From adding a feature to fixing a bug, from supporting ISO timestamps to displaying birthdays on the settings page, these are the questions I ask myself, and they help guide me from beginning to end.
We’ll work through an example here that includes a relational database, a backend that provides an API, and a frontend that consumes that API. Projects with different components will require slightly different approaches, but the general process here should apply to just about any software project.
Not every new feature requires a change to data, but you should always start here. Do you need a new table or column for the thing you’re adding? In some cases you may need new data but some or all of it can be derived from existing data. For example, if you want to display timestamps in your user’s time zone, you already have the timestamps (which can be translated in the UI) but you may not already be storing the user’s time zone.
Finish and test your schema changes before moving on. Even though your new schema may require a UI that you haven’t built yet, make sure you can insert the data into the database directly and then write a query to retrieve exactly what you need.
Now that your database is updated, it’s time to expose the new data. This might mean adding a new API endpoint or defining a new GraphQL field. In some cases, you won’t have made any changes to the data, but will still need to manipulate this interface.
As with the schema: plan, execute, and test your changes on this layer before moving on. You should now be able to update and access the data you need for this feature, or the buggy data from before you did this work should now be replaced with the proper data that you’ve fixed.
It’s time to present your work! If you were changing an existing endpoint, you may already be done—your user interface is already fetching the updated data. If you’re adding something new, start by doing the simplest possible thing to make the new stuff visible. I’m fond of just dumping JSON in roughly the right area of the page where it needs to be used, then navigating around to ensure that it’s working as expected. Focus on writing a clean and stable API call that will return the right information in every scenario. If you have automated UI tests, add a test ensuring that you can read this new data on the page, even though it might look like a mess right now. Try making another manual API call to update the data and make sure those changes are represented on the page, too.
Now your data changes and business logic are complete, and you have access to everything you need on the frontend. It’s time to implement the final user interface! Focus on visual correctness and optimal accessibility. When everything looks and works the way it needs to, remove your test display from the previous step, if necessary. Run through your manual tests again, and update your automated tests to take the new UI into account.
Working from the bottom up like this allows you to focus on one realm of functionality at a time, and often means less work overall. On very large tasks, breaking up the work into layers like this can also make it easier to share the load with your colleagues. It’s a good process! Bye!