All of you probably know the term “eventual consistency”. Definition from Wikpedia says: “if no new updates are made to a given data item, eventually all accesses to that item will return the last updated value”. I coined another term: “eventual crappiness“: “eventually all software will become crap”. How can we fight this annoying law of dev-nature?
Don’t you know this feeling? You start building “the next great thing” that will never become “the pitiful piece of crap”. But after some time you come to realize: “shit, I did it again”.
We had an interesting finding on our internal Slack channel lately: “this project is actually better designed and more pleasant to work with with each release!”. No way, how can this be? We started to analyze this phenomenon and here is what we found:
Always find time to think and discuss
Will your customer be happy about it? Well, it depends. If you tell him that you need 10h to THINK, not CODE, he will probably say that he’s paying you to write code and deliver software, right? But please tell me: who are you, an ENGINEER with expertise in software design, or a code monkey that only hacks some dirty spaghetti code while sipping a soya latte in Starbucks? I bet your customer would prefer a surgeon that has a plan of surgery before he cuts him open, not a hot-headed slaughter.
When we get a new feature request, we never just open Visual Studio and hack around. We open OneNote, where all our project knowledge is saved. Then we create a new note with feature name. Then we paste all information that we got from the customer. Then we create a checklist: an implementation plan! Once the plan is done, another developer looks through it and either accepts or rejects it. As simple as that: think before doing. Always. You’d be surprised how many stupid ideas never make it to code just because we first write in in plain English.
This couldn’t be done without a “safety time/budget buffer” in estimations delivered to the customer. It’s up to the business owner to make sure that everybody understands and accepts this. Actually: this is one of his main responsibilities. Without this piece of a puzzle, everything will eventually fall apart. If the “buffer” was too much and was not used, it is “returned” to the customer. This is extremely important – it builds trust.
ANY code is cheap. Self-explanatory, well-designed, tested code is what matters.
Review, criticize, give feedback
We often ask one another to take a look at our code before we merge our private branches into a shared code branch. And you know how often each of us is criticized? Almost every-single-time. Code review is not about shaking hands, saying how awesome we are and nodding our heads with blind approval. Code review is about finding weak spots and discussing about possibly better alternatives. When we say “this code is crap, we don’t want it here”, we don’t mean that the author is a lousy developer. We don’t have lousy developers in our team. It simply means that there possibly is a better way of expressing dev intentions. We understand that feedback does not need to be positive to be valuable. Negative feedback is what makes us better, what lets us improve. Never get offended by this! On the other hand: don’t be Linus when giving feedback:).
We always try to imagine ourselves reading the same code in 6 or 12 months. Will we understand what it does? Is it properly documented with tests? Are commits in Git granular and cohesive enough? As you can see, we don’t limit ourselves to only CODE reviews. Whole development process is important, so you should also pay close attention to version control and project history. You WILL need readable project history sooner than you expect.
These practices take time. And we all know that time is important. But! If you don’t waste time on other stuff, you will have time for what I am writing about here.
Do you ever create “deployable zip archives” on you development machine? Do you ever manually transfer them via FTP? Do you ever go to a web server to stop an application pool and replace your website files? Do you ever log into the production database server in the evening to copy/paste SQL scripts to update your DB? There is more: do you ever MANUALLY write release notes? Do you…
Well… you’re doing it wrong!
If you don’t do “continuous delivery” then no wonder you don’t have time for the important stuff. Do yourself a favor and aim for this: code -> commit -> push -> done. Literally, DONE. Everything else (build / test / deploy) should be done by machines. This is what they are for. Take advantage of the fact that they haven’t RISEN yet to make us their slaves. You’ll be surprised how much time you will get.
New features rarely “fit in” perfectly, nicely becoming another piece of a puzzle. How often are you forced to just smash it in and then look the other way, pretending that everything is still fine? Well, there you go: after several iterations, your software puzzle will fall apart. We’ve all been there, right? But one can’t expect a golem stand forever if it’s legs are made of crap.
Don’t expect it to be easy. Every time you modify your code, you might end up refactoring LOTS of it. And it’s perfectly fine. Once you discover that it could be modelled another way to better express your intentions: go ahead and consult with your colleagues if they also feel the same way.
Every developer and every customer (internal or external, that does not matter) should understand that: good design is eventually profitable.
But code is not everything. Processes are a subject for refactoring, too! Do you really need all these forms that developers are filling by hand? Do you need time tracking in several places? Can’t a smart automated process gather all data from all tools that you use and generate a daily report of “what was done by who and why”? Question your development process! There is a lot of time wasted in it, I guarantee.
Teamwork is KING
You don’t need a team of geniuses to deliver fine software. Only the most fortunate companies (the one I work for is one of them ;) ) don’t have lazy ignorant bastards that simply “don’t care”. But often regular TEAMWORK is enough.
When one developer falls short – another can step in. Without pointing fingers. Many pairs of eyes will catch more stupid decisions than just one pair of eyes – especially when it belongs to the decision maker. Multiple brains will figure out a better solution than a single brain, no matter how bright it is. Embrace that fact and encourage knowledge sharing in your team to get the fullest of your people. More than one person should work on each task – make it a habit. They don’t need to be working together all the time: 100% pair programming is inefficient, regardless of what you read on “pair programming dogmatist” blogs. But one developer’s work should be accepted and approved by someone else.
Don’t focus only on LOCs generated by the team. Focus on the long-term target.
You can call me Mr. Obvious: nothing in this blog post is revolutionary. But believe me: all of these things combined are sufficient to deliver high quality software. It’s not THAT hard. Also: please note that we are working remotely and can still apply all these rules. I believe it’s even easier when having whole team on-site.