Soon I will publish on GitHub a project I have been working on for a year, and which supports my own open publishing platform, Hub de Libros. It is a framework I named Mantra Framework, written in Node.js, and it allows creating highly decoupled components to tackle large projects that are going to evolve a lot, as I describe in more technical detail in my latest book, El Arte del Emprendedor Digital.
I hope to base many projects on this framework moving forward, at least all the ones based on Node.
I dedicate as much time as I can to both projects, with the help of some collaborators. In any case, analyzing Mantra Framework, I cannot help but be surprised by the nature of an activity like programming after dedicating myself to it professionally my whole life. In my early experiments I was only twelve years old.
My professional activity is split between business development responsibilities, dealing directly with clients, leading a development team, and also directly designing and developing projects like the previous one, in addition to everything related to the publication of my books (currently, five technical books and two novels).
Anyone who has read even just one of my books will know that everything I do is directly related to software development, more oriented toward products than specific projects for clients. In other words, I spend part of my time programming, which is where these reflections on the act of programming and the subtleties hidden in this activity and profession come from.
Certainly, programming is a polyhedral activity that can be considered simple, but it can also be very complex. As I often use as an example, it is not the same to build a shack as a skyscraper, nor to build something intended to last only a few weeks as opposed to something that must withstand years. And yet, paradoxically, you can succeed facing software from one side and from the other, although the cost is different, as we will see below.
Unless you set your mind to it, anyone can learn some notions in a weekend course and start making useful things, while the more experienced among us never stop having new perceptions and discovering details that surprise us in something we have been doing for years: “Ah, look, I had never noticed this or the consequences of doing this other thing this way… interesting.”
Just as an author always writes to tell something useful to others (entertainment, education, culture, criticism, opinion, etc.), in essence, programming consists of solving some type of problem using a device to also provide utility to others.
This means that, unless you program purely for play and fun — as I do sometimes for experimentation — we program to serve others. It does not matter how, in what environment, with what programming language, whether within a small or large company or as a freelancer: we always program to offer something to someone. In my opinion, this is the essential attitude developers should have: a vocation for service toward our clients, users of our projects and products, and anyone who consumes what we do. In other words, the end user is the most important thing, even though we often forget this in our day-to-day work.
To bring this into a more concrete context: years ago I focused personal projects on what I liked and confused that with what others might need. I corrected that in time, immersed myself in the entire lean culture (Lean Startup, by Eric Ries), and it is clear that now, in everything I do, I focus not only on a topic I am passionate about (such as everything related to literature and open publishing), but also from the perspective of the final user or client. Whether we like it or not, this affects the way we approach software because it changes the nature and priority of requirements.
On the other hand, we do not only serve a community, whichever one it is, but also our own colleagues who will one day inherit our code. In other words, we also program to make other programmers’ lives a little easier when they continue our work.
Your mission as a programmer is to make others understand your work as quickly and simply as possible. In fact, the better you do this, the more you can delegate and focus on what adds the most value.
In a way, the more useful what we do is, and for more people, the better things will go. Therefore, it is not about working more, programming more projects, but about focusing everything on scaling the utility they offer to as many people as possible.
Programming requires a level of abstraction that, I fear, not everyone is capable of developing, because problems must be solved by translating the solution using a programming language with its own resources and also its limitations. Obvious, but not so obvious that the generated code and its quality depend a lot on that level of abstraction. Just observe how a solution implemented functionally changes compared to one written in an object-oriented language: not only the result changes, but the developer’s way of thinking when approaching the problem. This is like a mental work paradigm that will make you solve things in a totally different way. Sometimes the developer is not bad; they simply have not yet changed paradigm.
We should abstract, yes, but I only point out that this is an additional skill developers must have, and that this does not make us special people by any means.
I think programming is simple: anyone who sets their mind to it can do it. But I also think that programming well is not easy, which is why those two-week courses that promise to make you an expert overnight seem strange to me. I know, it is just a commercial resource, of course.
Programming also has artistic connotations in addition to technical ones. Thinking only with the latter and not with the former always leads to a bad solution. I say this because, to program successfully, we need to deploy a huge amount of imagination and creativity beyond knowing the techniques and best practices we know we must use. Often, creativity consists of finding a simple solution to a problem that is not simple.
Unlike other disciplines, something else that can be strange is that when we program, we have to think a lot about doing it in a way that we can detect and correct errors later. Think about it: code design changes when we think about its maintenance, just as a car can be designed with future repairs in mind years later. For some reason, this issue is difficult for many developers I meet to really grasp, and if I extrapolate, I can only think that it is something widespread in our industry.
Inevitably, no matter how much experience we have, no matter how many thousands of lines of code we have written, we always program while making mistakes. Some are detected by syntax errors at compile time or runtime in interpreted languages, in addition to the bugs that will appear even if the code is perfect. I do not know of any other activity in which progress is made by creating something new while simultaneously correcting it continuously.
The consequence of this is that we cannot trust our code, and therefore we must support it with tests as much as possible. There is even a discipline, TDD, that programs by writing tests before production code.
Imagine an electrician installing a new building and making a wiring mistake in some switchboard: obviously, no wall will collapse and no window will break. But in software, yes. In software, a mistake somewhere can end up causing errors in the most unexpected place, which is why we need integration tests, validation checks, and more.
To summarize: the activity of programming inherently involves writing tests.
Surprisingly, writing tests is not a cost, but an investment that will allow you to move faster. Counterintuitive, yes, but subtle to grasp.
When we program, we struggle to pay attention to what I call the time horizon. Unfortunately, and I hope I am wrong, most developers only worry about implementing whatever is needed so that it works as quickly as possible and then delivering it to the client. But the nature of many projects is that they must last in production for many years and, more importantly, will be radically modified and will undergo a lot of evolution, not to mention the number of library or third-party dependency updates that will likely cause more changes in production code.
Once again, focusing on software in the short or long term has impressive effects on both its architecture and its design. The curious thing about this aspect of development is that the effort is similar; the only difference lies in the developer’s experience and their willingness to do things better.
It is also somewhat strange how small defects we leave behind (bad class names, redundancies, poor organization, long functions or methods, too many parameters, poor objectification, etc.)—however small they may seem—have a cumulative, devastating effect: if we do not go back to improve them continuously, sooner or later the quality of the project will suffer. This is what we call technical debt.
One thing I really like about programming is that a software project never really ends, even if it meets the client’s requirements. I mean, you will always find something to improve, simplify, or do better, new tests, etc. That is why, for example, I installed the latest update of Visual Studio Code today.
And this is good news for me, because it relieves me of the weight of having to solve everything in the best possible way at a specific moment and allows me to move on to other parts of the project, knowing that there will be time to revisit it again and again, as many times as I want. Of course, I do not forget to note all pending improvements in a task list.
Programming is an incremental activity: little by little, adding this, then that, then improving something that was not quite working, cleaning up another part, in an infinite kaizen process. In other words, we tackle a complex project through iterations: now this, then that, and next time this other thing.
However, some of those iterations should be left for improving everything done so far. This may seem like a waste of time; however, by lightening the technical debt we discussed earlier and improving the foundations and the way we advance the project —which may seem like a step backward—, we gain speed in development and consolidate the solution more in subsequent iterations.
But incremental also means we program functionality hierarchically, something that sometimes escapes us or is forgotten: we build functionality on top of other functionality, which is built on top of another, and so on through several levels or layers. This aspect, perhaps more subtle, also has a profound impact on what is called the architecture of the solution. Beyond that, what I want to emphasize is that if the foundation of a project is not solid, everything else will collapse under its own weight.
Another subtlety: the function of layer n is to make layer n+1 as simple as possible to implement. Think about it for a moment with some practical examples that come to mind.
Programming also consists of using certain recipes for typical problems in our industry: from architecture best practices to design patterns and everything related to usability. Designing software, just like building a house, requires mastering certain principles so that the final solution is not improvised or fragile.
The software development industry is very mature by now, but unfortunately the quality of the software produced in general is not. We have a huge amount of documentation about best practices of all kinds. If you follow them, your work as a programmer takes on a different color; however, these good practices are continually ignored, both in small and large corporate environments. It is in our nature as programmers to leave things not fully done even when we know they can be improved. Sometimes it is due to time pressure; other times, pure laziness. And sooner or later, that will come back to haunt us.
For me, programming is one of the few activities that allows me to enter that state of flow (flow), a term defined by psychologist Mihaly Csikszentmihalyi. This has happened to me since I was young, and it has led me to think that this activity is one of my passions and vocations. If something does not fully fill you, you will never enter that mental state I am talking about, at least not often.
A poor, inefficient design that generates a low-performance solution is sometimes solved by adding hardware to deployment: more virtual machines or containers, more resources, more scalable databases, etc., when what is actually happening is that the design and architecture of the software is deficient. What I mean is that a bad solution has a direct economic impact when we try to mask it with more hardware. Performance tests, as well as all profiling techniques and software quality metrics, help us detect this type of common problem.
Programming is also a highly collaborative activity. As we know, many projects fail not because their developers are not good enough or committed enough, but because group work issues fail: perhaps toxic environments, rivalries, poor labor policy, or impossible deadlines that can only be met by delivering real garbage. So a good programmer must also know how to collaborate with others in one way or another, and companies, for their part, should create an attractive and motivating corporate culture. The same developer, since what they do is an eminently creative activity, may perform poorly in an environment where they are uncomfortable and be a star in another that motivates them. What has changed? The environment, the working dynamics, the nature of the projects, etc.
You can program as a hobby in your free time, but making this activity your professional career is a completely different matter. To do that, you need certain skills and attitudes called soft skills. No matter how technically good you are, if you do not have these skills, things will surely go worse for you. I talk about some of them in one of my books, The Coder Habits: Los 39 hábitos del programador profesional.
Similarly, and this is something I still do not fully understand, programming is an activity that gives some people wings to display egoic attitudes and feel better or superior to other developers. Why? I have no idea. What I do know is that, besides being an immature attitude and one likely associated with low self-esteem, the best programmers I have known (engineers or not) have always shared a very humble attitude in their profession. On one occasion I traveled to the Microsoft facilities in Seattle and was able to talk with some of the team leaders developing .NET Framework at the time. They spoke in such a simple and humble way about how they were evolving it that I was surprised.
We are in the era of entrepreneurship, and even the F.I.R.E. movement (financial independence, retire early) has more and more followers. We live in a migration of everything toward the digital, as could not be otherwise, and therefore programming is the transnational language that makes all of this possible. As programmers, we have it much easier than other sectors to start businesses. So I do not understand why most developers still prefer nine-to-five jobs as their only option for working, although I say this only as a very personal impression.
Finally, it never ceases to amaze me how the same development environment can be used to create such diverse projects, from games to ERPs, web applications, or anything you can imagine. We learn to program in one environment and can use it to build virtually any type of solution. Is that not wonderful?
With the preceding brushstrokes, I hope I have given a clear idea that programming, at least professionally, goes far beyond writing code in any way.
Setting aside the differences, and with all due respect to the animal world, as an old professor once told me: even a primate can paint a circle on a canvas, but that is not the same as having artistic value… ;)