Smart {Code};

How Many Programming Languages Do You Need to Know?

How many programming languages do you need to know as a developer? The main reason for this question is that most newbies see a lot of developers out knowing multiple languages or technologies, and that is the image they associate with when someone talks about a software engineer or any developer in tech. In this article, I am going to try and give my view on the subject with the hope that you will find it helpful and informative.

Now I want to start by saying that this is a very subjective topic. If you ask different software engineers, you are probably going to get a lot of different answers, and it is hard and virtually impossible for me to give an actual number on how many languages you should know. Why? There are a lot of different reasons why someone would choose to go with a specific language or a specific number of languages. Rather than me focusing on telling you to learn, say, five or six programming languages, I am going to focus on the type of programming languages that you should know and what you will gain in terms of knowledge of computer science fundamentals from learning those programming languages.

. . .

Before going into the types, I think it makes sense to discuss why you might want to learn multiple programming languages, even if you are not planning on using them to build applications or work on projects. Simply put, it makes you a better and more well-rounded programmer. I find that you learn more about programming when you learn different languages. There is no way to learn everything about programming from one or two programming languages or languages of the same type. It is valuable to learn different types of programming languages because they introduce new concepts and new features that you may not have seen before.

Another big reason is that it allows you to have a lot of tools under your belt and be able to make a better judgment about what language or technologies to use for a specific project. After all, programming languages are just tools used to accomplish a task. Ideally, you want to use the best tool for the job, and if you only know one or two programming languages, you might not even know that there is a better option out there for what you are trying to do.

. . .

There are two main categories of programming paradigms, and I am pretty sure all programming languages fall within these categories. We have either imperative programming languages or declarative programming languages. Of course, there are more specific categories within those, but first, I will explain the two main categories. An imperative programming paradigm is one in which we tell the computer how to come up with a solution. The important concept in this type of programming paradigm is how to design an algorithm in the process of finding the solution to a problem.

A declarative programming paradigm entails stating facts, asking questions, and having the computer come up with a solution for us. In this type of programming, we are less concerned with how we got that solution but more concerned with if the solution is correct and what do we need as inputs such that it gives us that correct solution. A good example of declarative programming would be something like SQL. You do not describe how you are going to come up with the query. You need only type it out, and the computer gives it to you.

. . .

Programming Paradigms Within the Context of Imperative Programming

The main paradigms that belong to imperative programming are object-oriented and procedural programming. There are a few others as well. There are many different programming paradigms, but these are, kind of, the main ones. It is worth noting that some languages implement multiple paradigms. For example, Python implements both the object-oriented paradigm, as well as the procedural paradigm.

When you look at the object-oriented programming paradigm, you will notice that the idea is to represent the program as a collection of objects that store their internal data and have external accessing parts like a method. Object-oriented programming languages use principles like encapsulation, inheritance, polymorphism, and so on.


  • Features like inheritance can reduce redundancy and allow the same functionality to be used in multiple classes without having to rewrite it.
  • Programs are typically easy to maintain.
  • Code is easily reusable.
  • Some security benefits can be achieved through data abstraction that you cannot get in some other programming paradigms.


  • The size of your programs will be quite large.
  • It takes a lot more effort to design and create programs using this paradigm. This has to do with its complexity, in general, and the larger amount of code that you need to write it.
  • The speed of programs created using said paradigm is usually fairly slow compared to programs built in something like functional programming or procedural.

When you look at procedural programming, you will notice that languages in said paradigm execute a sequence of procedures, which are usually called routines or sub-routines. In case you do not know, a routine or subroutine is simply a series of computational steps that need to be carried out in a specific order. Procedural languages usually rely on block and scope. You will see keywords like if, for, while, e.t.c and these are used to implement the control flow of the program.


  • They do not require much memory to run.
  • They also work well with interpreters and compilers.
  • They have a simple structure and require a minimum amount of code.


  • They do not protect Data very well.
  • Error catching and debugging is pretty difficult.
  • A deeper knowledge of the language and computer instructions is required to write in a procedural language.

At this point, I have covered two main paradigms within the field of imperative programming. Again, the point of this is only to give you an idea of how programming languages differ, and again, why you may want to learn programming languages that are from different paradigms in that there are different concepts, advantages, and disadvantages to them.

. . .

Programming Paradigms Within the Context of Declarative Programming

Now within the field of declarative programming, there are three main paradigms, which are logic, functional, and database. To avoid repeating myself, I am only going to cover functional and logic paradigms. The database paradigm language would be something like SQL, and you can probably imagine why that would be a declarative programming language based on the explanations I gave previously.


The logic paradigm is based on formal logic and, essentially, lines that state a fact or rule about some domain. When you want to solve a problem, you ask questions or write queries that return results about the facts that you have declared. Logic programming allows you to express knowledge in a way that does not depend on the implementation. This means that you are not really telling the computer how to solve it but simply giving it a problem you want it to solve.


  • Facts or information is separated from how it is used i.e separated from the implementation.
  • It is useful for non-computational disciplines.
  • It is very efficient at proving the correctness of solutions.


  • It is not easy to learn or use.
  • It serves a specific purpose that is not appropriate for many of the tasks that you want to achieve.


Functional programming avoids shared data, state, and any side effects using only pure functions that return values rather than modifying the state of a program. This means that functional languages rely heavily on recursion and the passing around of functions as arguments and return values. This paradigm evolved from Lambda calculus and is implemented in some popular languages like Lisp, Scheme, Scala, and even R.


  • Pure functions always return the same result for the same input, making them easier to test, easier to debug, and easier to comprehend.
  • Functional programming also makes parallel processing and concurrent programming much easier.


  • It is hard to represent or implement some notion of state.
  • Recursion is used almost anywhere, which means that there are no standard loops and a lot of people do not like that.

. . .

The main goal of this article was to share these four paradigms and to illustrate that there are many different programming languages, each with a lot of unique features and use cases. Yes, some of the languages within some paradigms are outdated, and you probably will not want to use them. That does not mean that there is no value in experimenting with them for a few hours. I will leave you with a few languages that you could learn that cover those paradigms. I am not necessarily recommending that you learn all of these. I am simply trying to give you an idea of some languages that are in those paradigms that, I think, have some value in at least looking into.

Starting with some older programming languages, Scheme and Prolog are first in line, not that I would ever use them in any real-life project. I, however, think that learning the concepts of how the languages work can be beneficial. If you are looking to get into more modern programming languages that cover some of these paradigms, I would recommend learning Python or JavaScript. They are both scripting languages, and they are both dynamically typed. So, that already gives you a good introduction to a specific type of programming language that you can do a lot of projects in.

I would also recommend learning Java because it is a strongly typed language. It is also an object-oriented programming language, and it teaches you a lot about object-oriented design, good programming habits, and ways of writing production-level code that you might not get in, say, Python or JavaScript. My last recommendation would be to learn C or C++ because they are lower-level programming languages. In C and C++, you would need to use things like pointers, you would need to learn about memory management, and there would be a lot of programming concepts that you may not have seen in languages like Java, Python, or JavaScript.

. . .

Again, these are my thoughts and recommendations. There are a lot of other paradigms out there. The ones I have mentioned in this article are the main ones people use. You can do more research before deciding on the ones to learn. You do not have to learn all of them at once. Programming is not going anywhere. You have a lot of time to stretch yourself as a developer.

5 Design Patterns Every Developer Should Learn

In tech, most developers tend to think about a career progression as junior to senior, to lead, to architect and so on. To some extent, I think something is usually missing from that progression, technical proficiency. One can describe it as going from a consumer to a creator. Think of it like using something like React or Angular in the beginning, and then moving up that technology proficiency chain. From where you are just consuming that framework to where you end up creating a framework that is used by other developers, and they become your consumers.

To get to that point, you have to build up your skill-set, and you start with basic proficiency in your language of choice. From here, you work up to data structures and algorithms, and finally into design patterns. Design patterns are general, reusable solution to a commonly occurring problem within a given context in software design. They are reusable, extensible, and are of industry standards. In this article, I am going to go through five different design patterns that I believe every developer should learn.

. . .

Singleton Pattern

This pattern involves a single class which is responsible for the creation of an object while making sure that it is the only one created. This class provides a way to access it, which can be accessed directly without the need for instantiation of the class object. The most common reason for this is to control access to some shared resource.

As an example, the pattern may come in handy when doing things like a database driver. If you are over on the client, it comes in handy when you want to know the current state of the app that is in a Singleton. The advantage is that you can go and get to that data anytime that you want. The disadvantage is that once you have added that constraint, instead of everybody being able to go and access it directly, you have got narrow down to whomever the consumers are.

This pattern is one of the most misused. Singletons are for use when a class must have exactly one instance, no more, no less. Some developers frequently use Singletons in an attempt to replace global variables. For intents and purposes, a Singleton is a global variable, in that it does not do away with the global variable, it simply renames it. The use of a Singleton is uncalled for if it is simpler to pass an object resource as a reference to the objects that need it rather than letting objects access it globally. You, therefore, have to know and make sure that you are using it the right way and at the right time.

. . .

Facade Pattern

Simply put, this is a structural design pattern that provides a simplified interface to a library, a framework, or any other complex set of classes. A facade in the real world would be the front of a building, which it hides all of the internal mechanics of the building. These would be the insulation, the rooms, the plumbing, the wiring e.t.c. The facade pattern gives you the ability to put a nice external veneer on your app. Take a compiler as an example. It has a parser, a lexical analyzer, a tokenizer, and all kinds of fun stuff that no consumer sees.

The advantage of using this pattern is that it gives your consumer a good interface. You can also choose to allow your consumers into the internals if you wish. One of the things to watch out for is the possibility of an oversimplification. You may end up oversimplifying the interface of that compiler that it is no longer usable or valuable. Another thing is over verticalization. You may end up creating a facade that is so specific to a single use case that it is no longer generalized enough to be generally useful.

. . .

Bridge Pattern

This design pattern that lets you split a large class or a set of closely related classes into two separate hierarchies which can be developed independently of each other. Another way of explaining this is progressively adding functionality while separating major differences using abstract classes. A problem that requires this pattern occurs because sometimes developers try to extend subclasses in two independent dimensions. That is a common issue with class inheritance. The Bridge pattern attempts to solve this problem by switching from Inheritance to the object composition.

This pattern involves an interface that acts as a bridge between the abstraction classes and the implementation classes. In a development example, the bridge interface would be something like an API. This approach simplifies code maintenance and minimizes the risk of breaking existing code.

. . .

Strategy Pattern

This design pattern lets you define a family of algorithms, then put each of them into a separate class, and make their objects interchangeable. Consider a scenario where you have a code that is going to go and find customers, filter through them and then send out notifications to them via email and text. You can use the strategy pattern to significantly clean this up by taking the mechanics of getting access to the customer records, sending out the messages and emails, and then creating that as an infrastructure layer. Factor out the filtering of those customers into one strategy, which is the strategy that helps you find the target customers you want. Take the notification strategy as a different strategy which helps to decide when, where and how you want to contact those customers. You can then use that library or that system in a whole bunch of different scenarios, and it becomes much less stressful.

One thing you got to look out for on this is to make sure that you have decent default strategies. So in the case of our refactoring, we go and take the existing logic around the customer filtering and the customer send-outs and turn those into the default strategies, which people can extend later. Otherwise, you get a system whereby default, you are asked to do a lot up front, and no customer wants to do that.

. . .

Observer Pattern

This pattern is the most popular by far because it is almost everywhere. It allows for loose coupling between the publisher, that is creating events and the subscriber or subscribers that are listening for those events, and you can use it anywhere. The con on this particular pattern is that you can go overboard with it. If everything is communicating by events, you can get into nasty event loops, which make the code hard to debug and it just gets chaotic.

There are a couple of solves for this. One, do not use the same message bus for everything, have a specific purpose for each message bus. Two, keep these systems localized. If you are on the client and you have got a button, and it is an admitting and event, you are good to go. You do not need to go beyond that.

. . .

So again, as with all, all of these patterns, use them wisely but use them because most people understand those systems when they see them. For people, who are interested in learning the design patterns, these are just 5 to get started with as you get your feet wet. There are more patterns out there, and many tutorials online that can help you get a good grasp of the different ones.

Do not just learn or read about the different patterns, practice them at least in small projects. The ability to see where specific concepts might be useful in larger codebases comes only with practice, experience, and time. Do not be in a hurry to get as many as you can under your tool belt. If you do not get a pattern instantaneously, look for different explanations and tutorials online, and you will get the hang of it after investing time to research.

Writing “Clean Code” Is a Myth. Code Is Never as Well-Organised as You’d Expect

When we think about writing clean code, we often think of code written with purpose where each line is perfectly thought out. Code that was planned out before it was written. So well-planned that the first time we run it, it just works. No errors, no flaws, first go. But why is it that for most of us, when we write code, it is far from this ideal?
A lot of times writing code can feel like being in an intense battle with your machine. No matter what you do, the errors just keep coming. To make matters worse, the error messages are unspecific, which means that when you google them, you get nowhere. Your frustration keeps rising, and the bug that you thought would be a quick five-minute fix, ends up taking hours!

. . .

I think that the perception that we have of what clean code is and how it’s written is flawed. That perception is dangerous because it can scare off a lot of beginners. The reality of programming is often far messier, where you pretty much write a line of code and all of a sudden an error occurs in the old part of the codebase that someone really should take a look at and refactor, but since you’re under a time constraint, you end up writing a quick fix and list like that, the tiny feature that you were going to implement has become a complete mess.

Code will always be messy at first unless you’re working on a project where you’ve done all of it before, where you know exactly what to write and where to put it, which is sometimes the case. If you’re doing anything that’s new to you or that you haven’t done a thousand times before then the experience is a lot different. Do not worry because there will be code reviewers and assigned documents that are to help you write clean code.
At the end of the day, in most software engineering jobs, things are not as well organized as you would expect. Mostly, the code that you write on a day-to-day basis is subject to a lot of outside factors. I mean things like time constraints, old code basis that is not maintained or even other people’s bad practices.

The expectation that you’re going to be able to write a piece of code that works perfectly, and is purposeful every single time, is far from what writing code looks like. You should still, of course, aspire to do all those things, but in most companies, it’s not only your job to write a clean piece of code. There’s also a trade-off between writing clean code and being efficient. Thinking that every code you write has to be perfection is neither realistic nor what anyone expects from you. Trying to write perfect code is super inefficient because to do that, you need to spend so much time thinking through everything that you do, and that ends up slowing you down.

The way that you should usually work or think about your work is to write, refactor and review. That is, you first focus on writing the code and making it run without errors. After you’ve got to spend some time refactoring the code you’ve written, it’s easier to refactor existing code than it is to write it like that from the beginning. Finally, once you’ve spent a bit of time refactoring and essentially cleaning up your code, you can send it in for code review. After review, I would say that you have successfully written a pretty solid piece of code while also maintaining a reasonable level of efficiency.

What I’m mostly trying to say is that the perception that we have that clean code is equal to perfect code is usually far from the truth. That is why big companies have practices like code reviews. The first implementation of something is usually far from perfect. Even though it may be inefficient to write clean code from the start, it doesn’t mean that you shouldn’t try. The fact that writing clean code is inefficient is not an excuse for writing bad code. The aim should be to write the best code you can at the time.

As you write, you often know a fast and a sloppy way of doing something and the slower but more proper way of doing it. This is when you should opt for the slower, more proper way. Instead of writing three nested for() loops, it may be worth spending a couple of minutes trying to figure out if you could come up with or google a recursive function that could remove some of the loops.

I believe that most of us know when we are being sloppy and just cannot be bothered doing things the right way, even though we know how to do it the right way. This is when I would suggest spending that extra amount of time doing it the right way from the start. On the other hand, let’s say that we’re implementing a new feature. Usually, there are a lot of ways to implement the said feature. In this case, I would not suggest spending several hours trying to research the most optimal way of implementing that feature. Instead, I would prefer just implementing the feature in the best way that you can, and then spending some time on refactoring that and making your implementation a lot more elegant.

A trendy term right now is “action bias”. It means being biased towards taking action over inaction. That is how you should be thinking when you’re creating clean code, meaning you can spend time researching things and trying to do it better, but you’re biased towards taking action. I think you’ll be well off if you keep that in mind as you code.
The thing to understand is that clean code is the product of several people working on a project together and not just one individual. I believe a lot of people feel like crappy programmers because their code looks like a giant mess.