From the acorn grows the mighty oak
This tip is sort of an implementation of the YAGNI (You ain’t gonna need it) principle. I’m suggesting here that we turn YAGNI up to “software evangelist” level and then dial it back just one or two notches back towards real life. I’ve found that boiling off complexity to this extreme is a boon to the way I work from a productivity stand point.
When I’m working a new project or even just new functionality for an existing project the first thing I do is look for the smallest piece of functionality that I can implement that takes me closer to my goal. So on a greenfield project I almost always start just by clearing down my create-react-app generated pipeline. I get rid of the standard app that it builds for you and make myself a “Hello World” just to make sure I haven’t completely busted everything. I actually made a video of my process for this recently which you can check out here if you’d like.
From this simple beginning I look for the smallest component that I can sensibly make that takes me the furthest towards my goal. An example might be, if I’m making a Todo list app then the first thing I’m going to attempt to build is a component that displays just the text of an item of my Todo list. The key here is that the small piece I build must take me the as far towards my goal as I can within that small unit. So, if I’m building a discussion board, the first component I build will not be something from the login screen!
The goal of this approach is to “add a little clay” at each step until my master piece is complete. So, in the previous example, once I’ve got my Todo item then I set my sights on getting a Todo item list working. Then the page that displays the Todo item list gets some love. And so on and so forth.
I find that by working in this way I avoid the risk of building components that hang together poorly. The components end up far more cohesive and yet loosely coupled because the contracts of communication between components is something that is being shaped from the first line of code.
Beware: Brain dragons be here!
The only struggle that you may get from trying to implement applications from the bottom up is a cognitive one. Something that people have a tendency to try and do when they start building applications from the bottom up is they try to imagine your entire application from the bottom! Don’t do this, there’s a chance your brain may pop! Just focus solely on delivering your narrowly focused functionality in the form of the single component you’re building.
When using this approach will be implementing fine grained details so it is important that you take steps localise your thinking as well. In this way you can avoid you trying to fit every fine grained detail of the entire app in your head at once.
One of the major fears that most developers have when coming around to the idea of building bottom up is that they might hit difficulties in the way they’ve implemented their components later down the line. Well, there’s two factors that make a decent counter argument to this. The first is that your natural development flow when using this method of building software is going to lead you towards refactoring away from problems like this. The second argument is that, really, you’re probably no worse off than if you had have done the planning in the first place in terms of lost productivity.
Programming: Sponsored by Jenga
To address my first counter argument to “What if I code myself into a corner by starting with small components?” I’d like to share with you analogy that I use often and I think really helps to describe good software practices in many different ways.
I’ve often said that building software is like building a Jenga tower. You can absolutely build it quick and you can also build it high. But the quicker you build it the more often you’ll have to go back and straighten up what you’ve built so far. If you don’t, eventually, it’s going to be harder and harder to add blocks.
This analogy fits in another way too because the higher the tower gets, the more the base gets bedded in by the weight of the blocks above. So the longer you leave askew blocks at the bottom the harder it becomes to straighten them up without affecting the rest of the tower.
This describes exactly what you might be worried about with the bottom up approach to software development: “What if I find askew blocks at the bottom of my tower too late?”, But I’m here to tell you that the worry you have there is the pretty much the solution to the problem itself.
The fact that you’re aware of this threat, alone, is going to make you more prudent in the way that you build your software. When you add this self awareness when developing with the fact that the bottom up method allows for frequent refactoring, you have a winning combination.
Why is this method conducive to frequent refactoring you ask? Well in the bottom up workflow, with each step you’re only adding small pieces of functionality in the form of terse components. So, the ability to take a step back and refactor your “tower” comes quite easily because you aren’t adding much with each step. Also, the cadence of the workflow makes the times in which you should embark on these refactors all the more obvious frequent so as “your bottom blocks bed” they’ll bed nice and straight.
Building software in this way is closely related to the concept of the Red, Green, Refactor cycle from TDD. If you use TDD then you’re likely going to feel right at home building a component at a time like I’m suggesting. If you want to see this workflow in action you might like to checkout one of my App from Scratch videos where you can see me walking through many cycles of this workflow from start to finish (albeit without using TDD) on an app that gets deployed at the end of the video.
Fortune favours the brave
I won’t lie, there is an element of building things in this way that is a bit of a gamble. Basically you’re betting on the fact that you’re a better, more agile, developer who can handle the unforeseen as it arises and decisively act to reduce it’s impact.
At the same time you’re betting that you aren’t a code fortune teller of any kind and that if the unforeseen is on the horizon it’ll be there whether you planned for it or not. Because….it’s…unforeseen, you can’t see it, right?
In any development project your can take two facts as given. First is that things are going to change in your code base in ways that may impact it’s ability to deliver on the objectives that the software is being built to hit. We all know this to be true.
The second given is that your understanding of the business domain between now and when you cut code for any one piece of functionality is going to be better later than it is now. So if we’re admitting that our domain knowledge is going to be better later then why on earth are we trying to make decisions about how our software is going to fulfill those domain requirements now?! Doesn’t it make sense to make these decisions later when we know more?
But let’s play devils advocate and assume that your unforeseen disaster (somehow) has had an impact that has caused a component, or even a number of components, to require a rewrite. Seems bad. But I put it to you that at that point you haven’t lost anytime.
When you think about it you’re just spending the time saving you gained earlier when you chose to avoid prematurely planning. It’s unlikely that you’re going to spend more time doing this rewrite of the few problem components than you would have spent in hour after hour of mind numbing planning meeting in which, let’s face it, you probably wouldn’t have found the problem you’ve got now anyway.
On the flip side, think about all the time you save if avoiding premature planning was the right choice. If your implementation goes smoothly then you’ve just made what constitutes a double saving in time; once for not having planned this future functionality and once for allowing yourself to reinvest that time into furthering the project. I’m a big fan of deferring decisions till the last minute as I explained in my post about project architecture.
More to come