I was watching/listening to this great talk by Simon Brown on Modular Monoliths from GOTO 2018.
In this he mentions a term called Cargo Cult Programming and it really struck a chord with me.
I’ve recently joined a new company with a new programming language, new tools, new processes and a new team. Actually, it’s pretty much ‘new‘ everything.
This has caused me to do a lot of learning in recent months. Being relatively experienced, I like to look into the ‘whys’ rather than the ‘hows’ when learning new things. What I’ve realised is that this is not the most common approach.
When a user is tasked with adding to an existing codebase, extending the current solution, they will most probably check how this has been done previously, copying the approach for their solution. They may/will blindly follow this pattern as it’s how it’s been done before. Additional blocks get added on top of the tower, without questioning whether it’s the right thing to do. If everybody does this, this will eventually happen.
This is where the term ‘Cargo Cult Programming‘ comes from.
Wikipedia explains it like this:
Cargo cult programming is a style of computer programming characterized by the ritual inclusion of code or program structures that serve no real purpose. Cargo cult programming is typically symptomatic of a programmer not understanding either a bug they were attempting to solve or the apparent solution (compare shotgun debugging, deep magic).[1] The term cargo cult programmer may apply when an unskilled or novice computer programmer (or one inexperienced with the problem at hand) copies some program code from one place to another with little or no understanding of how it works or whether it is required in its new position.
Cargo cult programming can also refer to the practice of applying a design pattern or coding style blindly without understanding the reasons behind that design principle. Examples are adding unnecessary comments to self-explanatory code, overzealous adherence to the conventions of a specific programming paradigm, or adding deletion code for objects that garbage collection would have collected automatically.
A Common Problem?
Imagine a scenario where you’re working on a bug, finding the code that is causing the fault. You’re not massively sure what’s happening, so you;
- Google the error.
- You find a StackOverflow question.
- Search for the most upticked answer.
- Copy and paste the solution into your code.
- Try debugging to see if that’s fixed your problem.
It has, so you check it in and move on.
Sound familiar?
Why do we do that? Why do we blindly take this snippet and use it as-is, in our implementation?
The use case is probably not the same, so I’d be surprised if the solutions was. Simple examples aside, understanding the reasoning behind the solution is more important than the solution itself. There are many things you can’t do with something you don’t understand. You can’t modify, improve or test it. You can’t document it and you can’t own it.
Tech Trends, Buzzwords & Microservices
We all love what’s new, and management especially seem to like following popular trends, keeping up with technological advancement.
Most teams will now follow an Agile approach. TDD and Automated Testing can be very useful in certain scenarios, Continuous Integration removes much of the overhead from the infrastructure team, Big Data and AI can vastly improve user satisfaction and Containerisation and most recently Microservices shift our old monolith architecture into smaller self contained services.
Each of these advancements is brilliant in its own right, and I don’t condone any of them. My predicament is whether we need to adopt all of them into all our processes and code? We see blog posts from Netflix, Facebook, Twitter showing how their use has transformed how they work. If big companies deem them necessary, should we not too? This is where cargo cult programming rears its ugly head again.
We need to understand the problems with our current designs, why they happened, and how they can be jettisoned away in the future. Yes, these new processes may help us with our problems, but blindly following them in the faint hope that they do is not the way forward, nor does it make any logical sense.
I mention Microservices specifically as a lot of companies seem to be making the transition, citing such benefits as:
- Faster development time
- High scalability
- Easy to enhance
- Ease of deployment
- Autonomous teams with the freedom to choose technology
With a list like that, what’s there to think about? Let’s all jump on the bandwagon!
Wait a second… are there any drawbacks to this approach?
- Architectural Complexity
In monolithic architectures, the complexity and the number of dependencies reside inside the code base, while in microservices architectures complexity moves to the interactions of the individual services that implement a specific domain
- Operational Complexity
- How to provision resources in a scalable and cost-efficient way
- How to operate dozens or hundreds of microservice components effectively without multiplying efforts
- How to deal with a lack of standards and heterogeneous environments that include different technologies and people with differing skill sets
- How to deal with versioning
- How to track and debug interactions across the whole system
- How to keep track of hundreds of pipelines of code deployments and their interdependencies
These are lifted from Amazon’s own “Challenge of Microservices” whitepaper. Now I don’t know about you, but the drawbacks look a lot scarier to me than the benefits. Once again, I’m not saying this is not the right approach to go down, but unless these benefits outweigh the drawbacks what are you gaining from following this approach?
The ‘Public’ problem.
It’s simple really, Stop using the Public keyword, stop automatically creating Public classes. Why do we do it?
The problem with using the public keyword is you’re missing out on the benefits related to encapsulation. Why do we use it so much? It’s pretty much the default word we use when creating classes, all examples will use public classes, wizards and snippets will implement public classes. It’s time to stop. How many people have a public Facebook account? Most things in this world are private, as should our classes be. Make them private by default, and then if you need them to be public, change them then.
With great experience comes great apprehension.
The longer you are in a field, the less naive you are to perceived improvements that a new tool or process will bring. Most of today’s ideas come from decades old research into the field which are finally being embraced. Once something has gained mass adoption, it’s easier to feel comfortable with embracing it fully. That is, if it’s the right thing to do.
“Good judgment comes from experience, and experience comes from bad judgment”
- Rita Mae Brown
So feel free to keep on scouring the interwebs for solutions and tutorials to your problems; keep exploring new languages, frameworks and implementations. Just be aware of why they work, rather than simply how. We all learn from our own experiences and mistakes, so understanding the fundamentals will keep you from continuing down the same path in the future.