Photo by Paweł Czerwiński on Unsplash
tl;dr;
This conference video from HackConf Bulgaria 2019 (I attended yay) was the catalyst for me.
Bozhidar Batsov: The Groundhog Development Method
Intro
This post is entirely opinionated and is based on my experiences, please take it with a pinch of salt.
I apologise it is lengthy.
History
Since the beginning of time (1 January 1970 00:00:00 UT) programmers have been striving to write code.
For sometime we wrote very little code at all
Then we began to write lots of code (obviously not just for Hello World)
https://en.wikipedia.org/wiki/Plankalkül
Then programming began to get a little easier
https://ourcodingclub.github.io/tutorials/fortran-intro/
Fast forward sometime and you find yourself in the land of "high level languages" you know the simple stuff that even your wee old granny could write from her rocking chair...
That is an implementation of hello world in C btw
https://www.quora.com/What-is-the-most-complicated-C-code
Solution
I see where you are going with this...
The issue is the lines of code and the fact that as a native English speaker I can't properly say what I am trying to do with these languages...
We need more packages, we need more abstraction.
So we gave the world packages. We gave the world languages that were pretty much plain English. What did they do with it? They threw it right back in our faces.
"I amn't using a package it could have anything in it." - They say as they proceed to write the exact same code as in the package.
Dogfooding innit.
Then began the process I like to call "meme based programming"
Off topic, c'mon Grant get back here!
Anyways the point I am making is that as programmers... we suck... we write crap that we aren't proud of on a daily basis.
It's ok though because we always have a solution... right.
If someone was to hire me to write code with the processing power of a calculator, without my safety blanket of C# without ReSharper, without Google, without Stack Overflow to send a rocket to the moon I would end up with at least something on fire.
I still don't get it
Anyways enough memes and stuff...
The point is we will write some garbage, sometimes we can't control this. Sometimes that hot steamy garbage was the best thing we could come up with at that point.
But...
How often do you look at that hot steamy garbage and think "What was I thinking?"
Probably quite a lot.
But due to scope and other constraints you never do anything about it because hey "It works" - (TM) every programmer ever at some point.
Some solutions I try to use.
Lets say you have a little bit of "slack time" you managed to get that feature done a few days before expected.
There is a piece of code that you didn't write for this feature but it is in the same class or file that you are working in. It has been there for sometime. It is absolute hot garbage. I am talking this kinda code
https://levelup.gitconnected.com/reviewing-the-worst-piece-of-code-ever-db2df8730c76
"Most" of them are "easily" refactored but you can guarantee that I have written some awful code in my time. The kind that you look back at and think "Did I fall and hit my head that day?"
Take some time, refactor the garbage.
Before you do that find out something extremely important.
Does anyone actually use this garbage.
What I mean by this is...
Lets say your garbage code is on a page that 0.46% of users (<1%) actually visit. Is there much point keeping that garbage code page around?
If that 0.46% of users is the directors of the company then probably. Discover who uses what and why they need it.
This is possible if you:
A: Know the entire code base and your domain inside out.
or
B: Have excellent analytics and/or have "internal products"
Obviously sometimes the above is impossible due to external factors.
But lets say you can refactor 100 lines of absolute garbage into 50 lines of nicely abstracted method code.
GitHub will show this as a red PR and for me red PR's are the gold standard of PR's
Obviously in the above image I added 37 changes, a new feature, yay that's great, new code woo.
But I also managed to remove 4 lines of code. Doesn't seem like much but those 4 lines of code made that repo a bit less manageable. Scale that up to 400 lines and you have removed a real nice bit of your app.
Less code = less overhead = more time for the "cool" stuff
People talk about strangler pattern rebuilds/refactors where you identify core logic in an application and "strangle" down your application by lifting and shifting unnecessary pieces of logic out into microservices or packages until you are left with this really nice small, concise piece of code that is easy to manage and allows you to move really quickly.
This is just an ideology. Why should it be confined to the constraints of a rebuild.
If you apply that mindset to your working day or even side projects then you start to attack some of the parts of your repo that keep you up at night.
Lets say you know for sure that there is an absolute nightmare piece of code inside an API endpoint. It's sole purpose is to transfer data that isn't all that important to a message bus mechanism which is then picked up by a cron scheduled function to place this data off the bus into a database.
This code keeps you up at night because the cron function keeps erroring out because of network issues between the bus and your cloud provider.
Why can't you just refactor out that technology and handle the writing of this non important data directly in the API. It's not very cool for your CV but sleep is great for humans.
The above is probably the worst example ever, but what I am getting at is sometimes the "correct" choice is the most basic choice.
Because we removed our message bus and our cron function we can also remove our implementation of CQRS in the API. Bye Mediatr, Bye MassTransit.
We now have one very basic Entity Framework call. Our flow for this non vital data has gone from
User submits -> API -> DataSubmittedRequest -> -> HandleDataSubmittedRequest -> MassTransit -> MessageBus -> Emit Event -> Cron Function Picks up message -> HandleDataSubmittedRequest -> Entity Framework -> SQL DB
To
User submits -> API -> Entity Framework -> SQL DB
Ok sure now we have lost some fault tolerance if the DB write fails the data may be lost but that is the trade off to weigh up sometimes.
Sometimes allowances have to be made for simplicity but 99% of the time optimistic success will get you very far and your team will be happier as they don't have this overhanging fear of something complicated breaking on a Saturday night when they are having vino with friends.
I am 1 developer working on an open source project
If you get GitHub issues in on an open source repo (or you can apply this to your company, it is a little more difficult though) you have 3 options:
1: Blindly accept the suggestions and implement because if its important to 1 person it must be important to everyone.
2: Wait for more +1s on this issue and weigh up importance before implementing.
3: Be very firm with your core goals. Reject anything that does not align with these core goals or directly add value to these core goals. I.E my app does 1 thing and it does it excellently, no I won't add "Stories" to my app
Now option 3 probably won't win you many popularity contests but it is the option I would probably choose. If you begin to add features to applications do this with extreme caution.
The family hypothesis
Think about your application like a family:
You have 0 kids, no partner, you rent a really nice apartment in a cool part of town.
You look after yourself and that is it. Life is easy. You have great hair and enjoy reading and learning new languages.
Todo lo que necesito es vino y un gran libro.
Then you find a partner. A new "feature" in your life.
Now you share your time with this new feature. I apologise that sounds horrendous and I apologise to my fiancée, you are more than a feature to me 😂
You no longer learn new languages because the Duolingo owl "annoys your partner" instead you have both decided that you need to buy a house because you both want to add many new features.
You now can't drink expensive Chilean wines because you are in a code freeze to be in a great position to add a really nice big feature to your app.
I hope your still following because I am getting lost 😂
You buy your first home. A really big one you saved all your money to buy it.
Everything is great everyone loves your home. It is the best home they have ever seen.
Then a pipe bursts. You cry a lot. You have to code overtime to fix this issue.
After several days you have fixed the issue but because you have been so focussed on that you haven't spent any time with your partner so now you have an issue there you need to fix.
Many "I'm sorry"s later you have resolved your "partner bug" so you decide to add a new feature to celebrate.
This feature took a lot of time to build. Lets say 9 months or 19.5 sprints.
Now you have no time to maintain the core application, you begin to lose your hair, you now remember none of the Spanish you learned 8 years ago, your knees hurt a lot, the new young dev that we shall call "Node" scares you at work because you don't speak their language and don't have the time to become their friend even though you wish your application was more like theirs.
After a little bit of time you add another feature. This time you get through 2 features at once "twinned features" we shall call them.
You have no idea how you are gonna get through this backlog now.
Everyone tells you that your application is great now. The best app they know, 5 stars.
You feel burned out maintaining this massive monolithic application.
Your "home" feature develops a "hole in roof" bug. This is extremely expensive and has caused the "aaaah theres water everywhere" bug
You decide to run away to Aruba. You just wanted to build an easy application and enjoy life.
If only you had rejected that initial pull request.
The above example is obviously not real life but you see how its very easy to take something simple and low maintenance and turn it into something that seems "daunting and insurmountable"
Now please whatever you do. DO NOT APPLY DECREMENTAL IMPROVEMENTS TO YOUR FAMILY. You will probably end up in jail. "But your honour, I just opened up a red pr like the random blog post told me to"
Wow, thats morbid. I apologise.
Conclusion
I waffled a lot there.
I apologise for that but I was vomiting stuff onto screen.
This post could probably benefit from some decremental improvements.
In a nutshell.
Identify ways you can make your codebases smaller or more easy to maintain.
It will make your life easier.
Please delete cautiously. Don't delete the main app logic.
Somethings cannot be refactored. This is ok you can't win every battle.
Be cautious when blindly adding new "features" will this cause massive headaches months later for not much return.
Sometimes it is ok to push back. Fight your corner for why something shouldn't be added.
If a feature does add real value or it is business critical obviously you can't deny everything, we do still love to write code.
Great analytics help you to chop down huge code bases by seeing what's needed and what's not.
It gets me all warm and fuzzy when I delete huge chunks of code.
Hall of Fame
Comment your best refactors or biggest project deletions in this post.
Mines is:
12,490 lines deleted and 0 new lines added.
I wept that day. TEARS OF JOY
Anyways I hope this EXTREMELY long post has been of help to someone.
Thanks, Bye 👋
Top comments (2)
Have you looked into functional programming? It has been one of the most powerful ideas I have come across for writing more expressive code than doesn't involve insane layers of indentation or layers of poorly abstracted domain modeling. I'd encourage you to look into F# and would be happy to provide you some resources if you are interested.
This was a phenomenal essay, and I love the video too, watching it now. 😎