A slight tangent

A slight tangent
It's time for a quick detour

Just because we're building things in tiny little baby steps doesn't mean we're going to write our code blind.

One of the core tenets of the "clean code" and "test-driven development" movements is that you are creating something that is easy to change further down the line. But, just because it's easy to change doesn't mean you have no idea which direction you want to go in.

I've been thinking about this system for a long time and I've already implemented two parts (workflows and activity triggers) in my day job[1].

Plus, while well structured code is easy to change, relational databases are not - at least not without risk. So it's important to have enough of a plan to minimise the chance of you screwing up your customer's live database further down the line.

What I don't know

The file system

I want the system to have a file-system - a hierarchy of folders that contain documents. But I’m also pretty sure that some things - like Organisations - will actually just be a specialist type of folder. I also want to be able to use symlinks so the same folder or document can be referenced from multiple locations.

Calendars and appointments

I’ve built several simple calendar systems in the past. All were unplanned and all ended up being very messy. I’m sure there’s a better way.

What I know

The form builder

I’ve built several of these in the past and I’m pretty sure the structure I’ve got in my head will work. In effect, we’ll have a template that’s divided into sections. Each section is then divided into blocks - text blocks, image blocks - or question blocks. A form is built from a template and it displays the text and image blocks. However for the question blocks, it asks the user to fill in the details and stores them as values against the form.

Workflows

I originally designed my workflow system for Standard Procedure - but then Collabor8Online received a feature request and it turned out to be a perfect fit. C8O’s workflow system has the following concepts - Workflows, Stages, Options, Automations, Tasks and Statuses. Each slots together nicely and the whole framework has been proven with C8O clients.

Automations and triggers

The workflows will need to trigger automations - things that happen in the background. These will need to be configurable - either by me, or by the administrators who are managing the system - so they will likely be different for each installation. It also makes sense to extend these, so it’s not just workflows that can trigger an automation. Why not have more triggers? “When a folder is created, do X”. “When a timesheet is marked as completed, do Y”. “When the user taps this button on their dashboard, do Z”.

The activity feed

As soon as you have the system doing stuff automatically, you’re going to have support issues where a customer reports a bug because something doesn’t look right. As a dev, I can spend an hour or two diving into the Rails log files, figuring out what’s been going on, only to report back to the customer that it’s behaving exactly as expected because someone else in their office changed a configuration option two weeks ago. Or I can give them access to a simplified audit trail, showing them the actions that their users and the system have performed, so they can understand what’s going on.

Actions

In order to make this activity feed work, it needs to be hierarchical. When X happens, it triggers Y and Z. If you just have a flat list of “log entries” it might not be clear that Z happened as a consequence of X. But if you structure the audit trail as a hierarchy, you can navigate up and down the tree to see why everything happened. In Collabor8Online and other systems I’ve built, I’ve modelled this through a pattern that I used to call Commands (although I now think Actions is a better word for it). In effect, every significant action triggers an Action that is written to the database. This Action record may have a parent Action and may have child Actions - so this then becomes the audit trail for the system.

Other stuff

CanCanCan

Permissions are hard. No matter how simple you think your permissions system is going to be, they always end up very complicated with edge cases where two different schemes clash against each other. I’ve used CanCanCan a lot in the past as it centralises all your authorisation rules - so at least you’ve only got one place to look when things get complicated.

The "resource" API

I remember reading about Supabase and while I wasn’t that interested in what it did, what I did like about it was that it offered an automatically generated JSON API which took account of the current user’s permissions. Because it’s built on PostgresQL and Postgres has row-level permissions, the API could ensure that no data that the user was not permitted to see would ever be leaked into the wild. Then I realised that I could build the exact same thing, just using CanCanCan to control the row level permissions. So I’ve built some routes - you specify the class name, the model ID and maybe an association. And a single Api::ResourcesController figures out what you’re allowed to see and returns a JSON document containing just that. It’s not perfect and sometimes I need to add in specialist cases (and controllers) but it saves a ton of time and keeps my routes file nice and empty.

One step at a time

I’m also trying to make sure that, unlike some of my previous projects, this code stays clean and easy to change. We’ve all had systems where you fix a bug over here only to introduce three more bugs over there. This is because of a dirty system design (something, which unfortunately, Rails makes very easy to do).

So next time, I’ll be actually taking the next step at implementing our specification, via a quick detour on what causes these dirty systems and some principles we should follow to keep them clean.


  1. This is part of the reason they are so relaxed about me doing freelance work. They get the benefits they get as I explore ideas in other contexts. ↩︎

Rahoul Baruah

Rahoul Baruah

Rubyist since 1.8.6. Freelancer since 2007, dedicated to building incredible, low-cost, bespoke software for tiny businesses. Also CTO at Collabor8Online.
Leeds, England