The Problem with Popular Programming Languages
Every single year, technology publications produce their yearly most popular programming lists. And we programmers flock to those articles hoping that we picked the right language.
If our favorite language is in the top 3 or 4, we feel vindicated and validated, and feel we are somehow superior to all those peasant developers who clearly chose the wrong language.
The problem is that popularity is a terrible measure of quality or efficiency. You are choosing based solely on what everyone else is doing. Now take a minute and think about what the average person does in life.
The average person doesn’t exercise as much as they know they should. The average person is ignorant in many subjects. The average person eats poorly.
The list goes on and on. And yet no one thinks that they are below average. Why? Because average just isn’t good enough and below average is worse.
Now, let’s imagine that you want to improve your fitness. How would you go about it? Would you consult a list of most popular fitness activities to determine what level of fitness you should strive for?
- Sits on couch daily (48%)
- Walks to the car (23%)
- Walks the dog once a week (17%)
- Lifts groceries (11%)
And would you then ignore the items on bottom of the list as not worth considering?
- High-intensity Interval Training (0.3%)
- Running 3 or more times a week (0.2%)
- Weight lifting (0.2%)
- Yoga (0.2%)
Clearly, this strategy would be sub-optimal if your goal was to improve your fitness. So then why do we take this approach when picking a programming language?
You Have To Go Where the Jobs Are
Unfortunately, most of are a slave to the Job Market. First and foremost, we programmers gotta eat. So we learn the languages that have the most jobs. And some of these top-programming lists can help us see which languages will be required by most jobs.
But let’s not fool ourselves into thinking that we’ve chosen the “best” language. We haven’t. For most of my career, I chose what was going to be in demand years from now. I wanted to make sure that I was still going to be marketable years later.
And that certainly helped put food on the table, but it was not optimal. I suffered far too long in my career writing code in Object-Oriented languages before I decided to stop using Inheritance and ultimately Object-Oriented languages all together.
For more on the problems of OO see my Medium article Goodbye Object Oriented Programming.
These languages were all the rage and that’s what everyone else was doing so it made sense to work in those languages so that I could still get work.
This strategy works if all you want is work. But I must admit that, in many ways, it’s a terrible strategy. That strategy did not minimizing the pain and suffering I got working in faulty paradigms. But, unfortunately, for most of my career, I was not in a position to decide.
Someone else made that decision long before I was hired to work on their codebase. But what criteria did they use to decide? Most likely, it was the same one that I was using — popularity.
Making Better Choices
Only a very small handful of us get to decide for the rest which technologies to use. We few who are in these pivotal positions have a heavy responsibility to choose wisely.
But we don’t. Too often popularity is the number one criteria we use. But why? There are many reasons, one of which is the old adage that “No one ever got fired for choosing <insert popular choice here>”. Originally this saying was made about IBM and then Microsoft.
Another reason is because as a company, you want to be able to hire programmers who don’t need to be trained. Depending on the technology, programmers may need to be trained for 1 to 6 months.
Choosing to avoid this is short-term thinking since your company will probably live with your codebase for decades. Making a bad choice today just to avoid training people can doom your company to years and in some cases decades of unforeseen costs.
Look at how many programs are still running that were written in COBOL. I doubt anyone would’ve guessed that this code would still be in production some 40 or 50 years later.
Avoiding training costs in the short-term can turn into long-term costs that dwarf the short-term ones. I’ve personally experienced this with choices that were made by others before me and choices that I’ve made.
In the moment, the decision seems sound. You have a company full of X programmers and we cannot pick Y language because no one understands it. There will always be a few developers on staff who will learn it quickly. But what about the rest of the staff?
Also, when you need code done quickly, you don’t have time to research new languages so that you can pick the right one, i.e. the most productive and best suited to the problem. And you don’t have time to train the developers in this new language before they can start coding.
You want them to start coding immediately. And sometimes that’s a perfectly reasonable business decision, e.g. when you need to get to market quickly and you plan to throw away all the code from version 1, but this almost never happens.
Too many times “temporary” code or a prototype quickly morph into the final product. And now we are forever saddled with maintaining that mess and cursing the earlier short-term decisions that were made.
To make better decisions, we need to expand our criteria. We cannot just think of the here and now. We have to remember that every time we write a line of code, it becomes both an asset and a liability for the company.
We need to learn how to choose so that we maximize the asset and minimize the liability.
How to Choose
Any choice you make in life is based on your values. Understanding what you value is critical to being able to make good choices in life and in business.
Different businesses value different things. Hopefully, you’ve found a company whose values align with your own. If not, I’d suggest you find one that does.
Too many companies value short-term profits. They have stockholders and board members to cater to and future profits are a problem for another day and quite possibly for another person to worry about.
If you work for these kinds of companies — and I have — you’ll find that they quickly take on Technical Debt while they scramble to maximize profit and market value.
Typically, the CEO will push their upper management to meet certain fiduciary goals come hell or high water. That hell they are damning you to is Technical Debt, i.e. a mountain of code that was hacked out in a RedBull-fueled race to an artificial deadline.
While this approach can deliver product quickly, that code isn’t going away tomorrow. It will now move to its most expensive stage in life, maintenance. But have no fear, the CEO’s bonus was well worth it.
And long before the interest payments on that Technical Debt begins to cut into their quarterly profits, the CEO and his top dogs will exercise their stock options and either enter into an early retirement or go somewhere else and foist a similar mess upon a whole new set of developers.
But as developers, we don’t get any stock options or golden parachutes. We’re stuck with the mess and the burden of keeping the software working. This is why it’s so important to find companies who have the right values for long-term growth and survival.
Once you’ve found such a company, the technology choices and especially the languages we use can make a huge difference. Language isn’t the only choice though. Proper development methodologies must also be employed.
The best language on the planet can be derailed by poor development practices. We also need to know what our values are as software developers.
But what are the right values? If you’ve worked in software for any length of time, I suspect you can answer this question pretty well.
Here’s a list of only a few key values for programming languages that we should hold sacrosanct:
- Languages must reduce boilerplate
- Languages must have powerful abstraction to reduce programmer effort
- Languages should be robust at runtime
- Languages should have a mature ecosystem
- The compiler should help developers catch errors as early as possible
This list is just the tip of the iceberg, but is useful to help us think about what attributes we value when we choose a language to program in.
Notice how, “program in what we know” isn’t on this list. That’s because it’s not that important and since the industry is still in its infancy and we’re still learning what works and what doesn’t, there’s no definitive language choice for a particular problem set.
Not too long ago, we used to have go-tos in our codebase, which wasn’t as frowned upon as it is today. And in most modern languages, it’s not even supported. That doesn’t mean the compiler isn’t producing code that uses go-tos, it’s just that we humans aren’t trusted with them.
And that’s a good thing. Removing dangerous features from a language has and will always make for better software.
If you only stick with languages you know, then you’re going to miss out on all the new things we’ve learned from the millions of programming man-hours that are done each year.
Think about all we’ve learned since those COBOL programs were first written. None of those companies still relying on them have been able to benefit from the technological improvements we’ve seen in language development over the last 30 to 40 years.
Language Lessons Learned
What lessons have we learned over the decades?
Here’s a short list:
- Go-tos makes code incomprehensible (Spaghetti Code)
- Code should be modular (Separation of Concerns)
- Boilerplate code is bad (DRY and Refactoring)
- Global Variables makes code fragile, especially multi-threaded code
- Automatic memory management is superior to manual (Garbage Collection)
- Immutable Data and Pure Functions makes programs easy to reason about and robust
- Static Typing makes for more robust production software (Fail Fast and Early)
- Nulls are a burdensome and are a hallmark of a fragile language
- Recursive functions are safer than for-loops
- Function Composition is the ultimate in reusability (Reuse)
While it’s true that any language you choose can do the job, since they’re all Turing Complete, the language you choose determines the cost in programmer hours. It also determines the robustness and quality of the final product.
I’ve worked at companies where software was never done. There are two reasons for this. One is that we’re always adding new features and to some degree this isn’t bad if they’re done well. The other reason is because the software is fragile as hell and needs a team of developers just to keep it alive.
I’ve worked in both scenarios and I can tell you that constantly trying to fix fragile software is like trying to paint a house of cards. No matter how careful you are, it’s only a matter of time before the whole structure comes collapsing down.
So far, all of these lists haven’t honed in on a single language winner and for good reason. There are plenty of really good winners that have been designed to incorporate many, if not all, of what the industry has learned over the last 20 to 30 years.
But there’s a bigger aspect about languages that we have yet to consider and that’s Paradigm.
Not All Paradigms Are Created Equal
How we think is so important not only in programming but in life. Once we’re given a new perspective, it can completely change the way we think, and hence, how we interpret our world.
Many programmers learn a single paradigm and then promptly stop looking for others, defending theirs religiously. This only dooms them to being stuck in the past.
New ways of thinking don’t always pan out. Better ways, however, do. But how do you know the difference? Typically, only time can tell. Then how are we to best decide when we encounter a new paradigm?
A paradigm is just a model and with all models that we encounter in Math and Science, we judge them by how well they map to the problem they’re trying to solve.
The Object-Oriented paradigm tried to model the real world and it’s my opinion that this approach is why it fails terribly for programming.
We do far more in programming than model real-world objects. That’s only a fraction of what we do but it’s so pervasive in OO that it does so at the high cost of everything else.
What we need is a model of computation and logic. And with that model, we should be able to model the real world. And we need a model that is time tested.
The paradigm which ticks all of the boxes in our values list and is time tested is Functional Programming. Unlike past paradigms, it’s rooted in Mathematics that has been around for decades to hundreds of years.
The biggest problem most have with this paradigm is the four-letter word (or five-letter depending on which country you live in), MATH.
Many people have a huge aversion to Math and many programmers think that they’re not good at Math. I’d argue that if you’re a programmer and you think you’re not good at Math, then you don’t know what Math is.
Math is what we do all day. We just don’t think about it as Math. But it’s Mathematical Thinking just the same. Unfortunately, most of us remember our struggles in “Math” class and wrongly assume that we are bad at Math.
It’s true that most humans are terrible at the kind of “Math” we did in Math class and for good reason, we are not calculators. I cannot speak for other countries, but here in the good US of A, we still teach “Math” as if we’re going to churn out a bunch of human computers ready for a 1960’s job market.
Too many years are wasted in Math classes doing mundane calculations and very little time spent on Mathematical Thinking. But if you’re a programmer, you’ve somehow garnered this skill and that’s all you need.
Sure Functional Programming has its roots in Math and if you love Math, you can certainly take a deep dive into those areas. But a deep dive it’s not a necessity.
If you’ve made it this far in the article, you may be thinking that Imperative Programming languages are just as Turning Complete as Functional ones and you’re right. But they have vastly different perspectives.
The skeptical reader may be wary of this new fangled paradigm, but the truth is that this paradigm has been around far longer than what we use today. You may be wondering that if it’s so great then why are we still all using the Imperative paradigm and not the Functional one.
Well, I suspect there are a few reasons for that. Firstly, Imperative Thinking is more natural for humans. Surviving on the plains of Africa didn’t require much Mathematical Thinking, but Imperative Thinking was a survival skill.
It allowed us to simply perform complex tasks and solve complex problems. And by complex, I mean a multi-step process for obtaining food, e.g. find a long, straight stick, remove leaves, sharpen end, throw at food.
This step-by-step process is both easy to learn and teach. It’s our natural way of thinking. But as our world grew in complexity, more sophisticated ways of thinking became far more beneficial. But evolution moves far more slowly than technology so we must learn what is unnatural for most of us.
Another major reason Functional Programming has taken so long to take off is that the Math was worked out long before the hardware could keep up with it. LISP was one of the earliest Functional languages (even though it has Imperative features). In the early days, the hardware couldn’t keep up and so they had to build specialized hardware to run it efficiently.
But as hardware has gotten more powerful and software has gotten more complex and costly to maintain, adoption of Functional Programming has been growing at faster and faster rates.
In fact, you can find Functional features in nearly all of the most popular languages. This is very similar to what we saw years ago as Structural Programming was the new paradigm (something we now take for granted).
All the non-Structural languages starting adopting Structural Programming features. This also happened with Object-Oriented. Remember C with Classes?
This adoption can be found anytime a new paradigm shift is about to happen.
The Future is Now Old Man
I’ve been programming for 40 years. I’ve written in Machine Language, Assembly Language, and debugged my code with an Oscilloscope and In-circuit Emulators.
My first computer was an Ohio Scientific Challenger 4P with 8K of RAM and 8K of ROM, and I saved my programs onto a cassette tape.
To many of you, I am an OLD MAN. But let this old man tell you a story. When I was 19 and programming at my first programming job writing Z80 Assembly, I worked with another programmer who was 30.
He had already gotten set in his ways and as a snot-nosed 19 year-old, I saw him as a dinosaur. I swore at that moment to never let myself fall into that trap.
I would always be on the cutting-edge of technology and always would be looking for a better way. There have been times in my career where that wasn’t always the case.
It’s easy to get distracted by business concerns and life, but that would never last long. I’d always raise my head up, look around and see what’s new and improved, and more times than not, dedicate myself to staying relevant.
This has kept me marketable through both good and bad times, and there have been plenty of bad times, e.g. the market crash of 1987 or 2008.
I’ve gotten pretty good at predicting the next move of the industry. In my younger days, I’d jump on anything that looked new and exciting. That doesn’t always work out.
Now, I use my years of experience to temper my excitement and I’m a lot more efficient than when I was a young pup. Newer isn’t always better. Many times something that seems new is just a rehash of something old.
Every time I embrace a new technology, it comes with its pros and cons. Functional Programming came with so many pros that I didn’t consider the cons until much later.
What are those cons? Functional Programming is hard to learn — too hard to learn for many. I failed to learn it after multiple attempts. But why?
Well, I wrote another Medium article chronicling why and if you’re not sick of reading by this point, you may want to take a look at Why is Learning Functional Programming So Damned Hard?
In a nutshell, there are no good learning resources. You have to cobble together a curriculum from dozens and dozens of sources just to get a glimpse of the whole picture.
This is why I spent over 2 years developing and writing a book, Functional Programming Made Easier: A Step-by-Step Guide, which I used to train developers at work.
This book is a complete source for learning Functional Programming with the only pre-requisite of having some Imperative Programming skills (at least 2 years).
I’ve also written a 6-part series on Medium to give readers a gentle introduction into Functional Programming called So You Want to be A Functional Programmer.
Functional Programming languages are the least popular, but just like the nerds in school, they are going to change the world. They already are changing your favorite language.
Functional Programming is a technology that was developed by Mathematicians and Logicians decades before the computer hardware was ready for it, and decades before the Software Industry needed it.
It’s a technology that’s best suited for what ails today’s Software Industry, viz. bloated, fragile, difficult to maintain, complex software that costs the industry billions each year just to maintain.
Can this new paradigm fall into the same trap as all the others that came before it? Yes. Any good paradigm can be implemented poorly, but if done right, it is the best thing this old man has seen in his entire 40-year career.