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.
Top comments (6)
I've seen it a lot, when helping people with programming, that at some point they face an issue that can be solved by adding some sort of keyword, like
local
in Lua for example. Even though I always explain why this is necessary, it happens all too often that, later on, they face a different issue and, when asked how they'd go about fixing it, the first thing they try is just adding the same keyword again.This showcases a very common but harmful mentality of just repeating the same steps that helped in a similar situation. No doubt a valuable mental tool for the longest time during human evolution, but sadly one that backfires more often than not in programming.
I think this mentality, when applied to a larger scale is what leads to cargo cult programming, and on an even larger scale to the overuse of patterns where they aren't really apropriate.
It's good to use mental shortcuts and save energy for your actual development process, but when you have the time and energy, always ask yourself: How does this problem work and how does this change fix it?
Couldn't have said it better myself.
Thank you for this article. As developers, we seem to be a lot like crows flocking to each new shiny object ...
Thanks for the comment, We do need certain people to try out these new shiny objects. Just not all of us!
That's a nice article, I liked much.
Thanks, Glad you enjoyed it!