One of the more rewarding aspects to programming as an intellectual hobby is discovering new programming languages. The more exotic or novel or opinionated the language the greater the opportunity to learn something new that can be leveraged for more efficient and capable problem solving in the future. However, the down side is that once you put down the lens of intellectual hobbyist and pick up the lens of software engineer and professional, then you have to focus on a completely different set of programming language characteristics. Very often this means that you don’t get to directly make use of any of the non-traditional programming languages that are out there.
However, just because non-traditional programming languages will often not be applicable or appropriate for your client’s requirements and needs, doesn’t mean that there will never be scenarios where expertise in a non-traditional programming language will not be highly beneficial. Here’s some guidelines and considerations to help to decide when a project could use a non-traditional language.
Traditional vs non-traditional
Most have a good intuition concerning what constitutes a traditional and non-traditional programming language. However, it’s worth spending a minute to consider what actually sets these languages apart and how this is more of a spectrum than it is a binary categorization. Context is pretty relevant here. Using the C programming language for web development doesn’t make a lot of sense and using JavaScript to do embedded work also doesn’t make a lot of sense. If you change your domain, then what programming language is considered traditional can also change.
The biggest single determiner as to whether a programming language is considered traditional in any given domain is the amount of work other people are willing to do for your benefit. To better consider what this means think about what it means to use the C programming language in an embedded environment. C compilers can compile your C source code on basically every hardware architecture in existence. And if a new hardware architecture were to show up tomorrow, you can pretty much bet that it’s going to be accompanied with a C compiler. And if you wait a while someone is going to add the new architecture as a target to open source C compilers like GCC and LLVM. The C programming language is a traditional programming language in embedded programming environments because people and organizations that you are not affiliated with in any way are willing to write C compiler backends, put up tutorials and answer embedded C questions online, and produce libraries (free or otherwise) to accomplish your embedded C goals.
However, if you were to use the C programming language for web development then you would be walking a path more or less by yourself. There will be very few libraries to accomplish your goals unless you write them. If you encounter a problem, you will not meet anyone else who shares the problem so you will be working on a solution by yourself. Changes to how to interface with the web will be made and nobody will consider the impact to you. You won’t be notified and staying compatible with the rest of the world will be your sole responsibility. The C programming language is a non-traditional web development programming language.
I also mentioned that this is more of a spectrum than a binary categorization. We can imagine C as being one of the best options for embedded development (arguments can be made that it isn’t, but let’s pretend for the sake of thinking about traditional programming languages as a spectrum). The C++ programming language is going to be less good for embedded development than the C programming language. The standard library can be kind of big and there are some features (like exceptions) that can be kind of weird on certain embedded architectures. However, if you aren’t using the C programming language for embedded development, then you’re probably using the C++ programming language. Similarly, the Lua programming language was specifically written in the C programming language with an eye towards compatibility. Additionally, the Lua programming language is very small. The authors wanted it to be able to be used in embedded contexts. However, it’s going to be a less likely candidate for an embedded project than C or C++. Finally, programming languages like Perl, Haskell, and Scala are going to be the least likely to be chosen for an embedded project. It is certainly possible to use one of those programming languages, but you’ll be doing all of the work yourself.
Why we need to almost always use traditional programming languages
Before talking about when you should try to use a non-traditional programming language, we really need to look into why we need to almost always use a traditional programming language. The reasons aren’t really intellectually interesting, but they are important for being successful. And when someone is paying you to do a job, you really need to keep a keen eye on being successful with their resources and goals.
The biggest reason to us a traditional programming language can be summed up in the saying: “Amateurs talk strategy; professionals talk logistics.” The client needs to plan for many different eventualities. What happens if your company suffers a catastrophic financial disaster and goes out of business? Your client will surely feel sorry for you, but at the end of the day they need to find someone to complete the work. What happens if after the project is completed there is a change in some communication protocol and the client now needs some maintenance work to keep the project in working order? The client needs to know that someone is available to do maintenance work and can’t rely on your company having capacity to perform the work.
In these scenarios your client is more likely to be able to find some other vendor to perform the work that your company can’t (for whatever reason) if the project was originally completed in a traditional programming language. I know that if a client came to me asking that I complete or maintain a project started by another vendor, that I would be much more likely to take the work and give them a reasonable bid if I knew that the project was in a traditional programming language. Even when there are good strategic reasons for a project to be done in a non-traditional programming language, your client is going to have logistical benefits from having the work be done in a traditional programming language.
The fastest and easiest way to write source code is to find out that someone else has already written it for you. Even if you have some non-traditional programming language in mind that provides benefits that dominate the logistical concerns of your client, you still have to actually write the source code yourself. However, if there exists a library that is well maintained and already does everything that you want, then that solution is almost always going to beat anything that you do by yourself.
Security researchers are going to focus their time and energy in finding security defects in software that is popular. Similarly, the fixes to security defects are going to be quickest to appear for software that is popular. If you write a custom component that has a security defect, then you might only discover that fact after it has been exploited. However, if you reuse highly popular libraries and frameworks, then your client gets security checks and fixes for potentially free.
When we need to use non-traditional programming languages
The best reason to use a non-traditional programming language is the same reason to use a traditional programming language. Someone has already done most of the work for you. This scenario is going to be more common the more niche the domain you are in. Typically, you expect that traditional programming languages will have the libraries you need more often than non-traditional programming languages. However, if you’re in a niche domain then you can get into the situation where almost nobody is writing libraries to help you solve your problems. The best course of action may be to adopt a non-traditional programming language because that’s where the solutions already exist.
The next best reason comes from non-traditional features that the programming language supports. This comes into two major flavors. Features that add something and features that take away something.
A feature that adds something to a programming language should be adding something that specifically helps address some issue found in your domain. A good example of this would be the Erlang and Elixir programming languages. These programming languages have amazing out of the box support for concurrent and distributed programming. There’s a quote by Philip Greenspun that explains the principle, “Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.” Effectively, this is a restatement of the “use work other people have already done for you” principle that makes traditional programming languages so attractive. Previously we said that a non-traditional programming language might have a library that allows you to make use of this work. However, sometimes a language feature can be just as important as a library.
Let’s consider the Erlang programming language example. Concurrent and distributed computing is widely known to be difficult to do correctly, the source of Heisenbugs, and can cause even most seasoned professional to throw up their hands and give up. At some point you need to ask if it’s worth implementing your own “ad hoc, informally-specified, bug-ridden, slow implementation” of Erlang or if you want to get some high-quality work done for your client.
Features that remove something from a programming language are a little bit strange when you first encounter them. The natural intuition is that more is better. However, everything has a cost even things that are otherwise completely beneficial. In the case of programming languages the cost of adding features is cognitive load and complexity in verification. Removing a feature can sometimes make understanding source code and verifying that it is correct easier. You’ll need to reach for non-traditional languages that remove features when you’re dealing with a project that has very complex business logic.
The two best programming languages to consider when thinking about removing features are Rust and Haskell. Rust removes multiple ownership of objects and Haskell removes mutable state.
Sometimes logistics doesn’t matter
So far the reasons we’ve been exploring the use of a non-traditional programming language have been because the non-traditional programming language offers some aspect that gives it a logistical boost over the traditional programming languages. However, there are scenarios where logistics aren’t as important.
Prototypes are an excellent example of when logistics are less relevant. With prototypes you are encountering a scenario where the correct course of action is not obvious and what you want to accomplish might not even be possible. Almost by definition you’re not going to find libraries that perform the needed actions because if those libraries existed, then you would know that what you want is possible. Maintenance is also not relevant because your goal is a proof concept.
Volatile market forces can also make logistics irrelevant. In a scenario where you need to have a product released as soon as possible, ensuring that any logistical concerns are addressed may simply be more time and effort than you can afford spending. There are costs to operating in this manner, but sometimes you either have the choice of paying those costs or not participating in the volatile market.
Staying competent
One of the nicest things about a traditional programming language is that they tend to have good support. They’re championed by large companies with large budgets, they have committees staffed by industry leaders, or they have large communities filled with gifted and devoted maintainers. As a result, the traditional programming language can expect to slowly but surely acquire new features that allows it to stay relevant with modern software engineering practices. Where does a new programming language feature come from? It comes from a non-traditional programming language.
Building a good intuition and process around new programming language features is an important skill to have. Especially when you’re working on a large and long-lived project. This is made much easier if you already have experience using the new feature in a non-traditional programming language that already has it.
If you can justify using a non-traditional programming language either because there is some aspect of the programming language that directly helps your client’s logistical needs or if logistics are not relevant for whatever reason, then choosing a programming language that makes use of features that are likely soon to be included with the traditional programming languages of your industry is a great way to turn an immediate benefit into a longer-term game changer for your clients.