/ decoupled-systems

Code Generators - Happiness Is A New Chunk of Boilerplate Pt I

In this series of articles Rhys Watkin looks at code generators and compares the practical application of code generation tools for the production of frontend and web api projects.

Production Line of Bottles
Photo by KoalaParkLaundromat / Pixabay

We've all set up new dev projects. You know how it goes.

git init

Set up the initial project layout.

git add
git commit -m "initial commit"
git push

Then do the real work.

What happens in that 'initial layout' step? Do you copy something that works elsewhere; do you select that cool new framework you've been wanting to play with; do you find yourself thinking so-what, it'll change when we do the real work anyway?

This series of posts will look at decisions in that initial step that may make life easier down the line in the 'real work'. In particular, I'm going to look at benefits - and drawbacks - of using code generator toolchains to create and, just as importantly, maintain project structure.

To make this a little more concrete, I set out a clear, specific objective:

How far do generators get me to a REST API back-end, and a front-end website talking to it?

  • Spoiler: feathersjs and Vue get me quite far

I want to get my hands dirty so I'll add some requirements (and non-requirements, and opinions).

Firstly, I am actually asking for two (logical) applications: a back end and a front end. This is because I sometimes have control over only one or the other of these on real-world projects, and sometimes one side has to integrate with a 3rd-party complement.

Secondly, I'm asking for an interface between the two. Although I mention REST I haven't actually specified what goes over the wire: all I've done is hint at a URL-aware web service of some kind. To realise this, let's impose a requirement on the data format. I'll ask for a list of zero or more User entities, to be returned as JSON.

Given HTTP GET /api/users

Return json:

{users: [
        {  
            id: number,  
            name: string,  
            age: number,  
            emailAddress: string  
         },  
         { another user } , ...     
    ]  
  }

and given HTTP GET /api/users/<id>
return the same structure but with only a single user object thus:

{ users: [ /* one user */ ] }

(Putting breadth of technologies over depth of analysis, I won't consider the other REST methods here.)

I asked 'how far'. I would be astonished - and pleased - if a toolchain offered exactly the "right thing" out of the box. What I'm anticipating is some manual massaging of the generator's output (or, more likely, the output of several generators). What I'm observing is how much massaging I am required to do, and in a subjective sense deciding whether that extra work is acceptable.

There are of course many topics I won't be talking about here. This includes areas such as: basic installation, back-end persistence technology, site security, testing, build toolchain, anything tangential to generators. Even so, if I wrote out everything longhand and typed it in (and who says I don't ;-) ) I'd still need to consider these things. The exception, as we'll see, arises when generators are comprehensively opinionated. If you would like me to go into more depth on any of these other topics, though, please feel free to mail in or comment.

Before I get stuck in I should really consider an outstanding problem with data returned by REST APIs. We're all familiar with REST URL patterns like /thing, /thing/, and so forth, noun pluralisation, and mappings to HTTP verbs. What isn't at all obvious - to me - is the data-structure any of those methods should actually return. In particular, what data structure should HTTP GET /things actually return (assuming I asked for JSON)?

It turns out that nobody can agree. These guys have a proposal, but none of the generated implementations of REST considered in this post adhered to it by default. Furthermore, none of these offer the kind of parent-child resource relationships that REST is supposed to provide (RIP HATEOAS?). As I've said above, I set the objective to model working against an interface I don't fully control; and it seems that RESTlessnes, for want of a better term, provides another reason.

One last word - the aim of this series is not to be comprehensive. I won’t be covering Yeoman, for example. I discounted its tools largely due to the (inevitable) lag between a framework and any non-official yeoman generator; instead I focused on what framework authors themselves thought to give us. That said, if you know of other toolsets you'd like to advocate I'd be very interested in hearing about it.
All major initial problems having been considered, the next two posts will consider the back and front-ends independently.