Mathijs Sonnemans

Developer experience is a subject long overlooked. We all agree that developer experience is important, but it often gets buried under other tropes in software development. This is because until now we only really view the developer experience as a convenience. Something that is solved by the use of proper tooling i.e. git for version control and a wide range of different code editors.

But the process of writing code is often misunderstood. To some it might seem like following procedure, as if building a piece of IKEA furniture. This is not at all the case. It’s a more interactive process where the developer is continuously engaging with the meaning of code and how their lines alter the code around it, more akin to working on a piece of art. Developer experience is therefore more affected by the existing code that the developer is interacting with rather than the tools that they are using. If this idea clicks with you, it will allow you to write more maintainable code more efficiently. Thus ultimately allowing you to create better software.

The myth of ‘good code’:

What is good code? Within the field of software development there is probably no other topic that has been as furiously overdebated. Many have understood already that good code is about being easily readable and comprehensible; that good code is performant and consistent, that it is reusable and maintainable. I’m sure you have heard these words many times before. Most articles and talks on this topic will provide numerous heuristics of good code. Comments - not too few, not too many; indentation - use it at all times but don’t go too deep; naming - be explicit but don’t give your variables lengthy names! And for Linus’ sake separate your concerns! I think that for all but the people who are just emerging themselves in the world of software development these ideas are widely known and accepted. Yet in practice we can have endless discussions about them. I sense that this is because the sheer plurality of heuristics we ascribe to ‘good code’ inhibits us from consistently applying all of them. Every developer weighs these heuristics differently and will thus experience the ‘goodness’ of every piece of code differently based on their own opinions.

Automation is a substitute for an otherwise labor intensive task, mostly driven by economic incentives. From a utilitarian perspective good code is therefore measured by its economic efficiency. We are in the business of automating things. Whether that is communication between entities, solving complex problems, or giving someone an interactive experience, the information revolution has given us the technology to make these processes magnitudes more efficient and less labor intensive. In the previous epoch, the industrial revolution, mechanical engineers made the production of goods magnitudes less labor intensive using the power of steam engines. What sets us apart from the mechanical engineers is that our innovations don’t have physical representations. They are merely abstract ideas which are legible in the form of code as instructions to these universal machines. Our goal, however, remains congruent to theirs. Because there is an economic incentive to increase the efficiency of a certain physical process, we program a machine to do it for us.

The industrial revolution
During the industrial revolution, mechanical engineers developed machines that drastically increased the economic efficiency of production. Today, software engineers essentially do the same with all aspects of life. Image by @museumvictoria - Unsplash

We can conclude that good code satisfies all its features, runs efficiently and the time it takes to develop and maintain it is minimized. We shouldn’t be oblivious to the fact that the ‘goodness’ of code usually stems from its economic value and utility. This explains many of the heuristics previously discussed. That code runs efficiently and satisfies its features are never really debated when we talk about good code, because this is a given. Good code is maintainable and reusable because we understand that the required features of a project change over time, and our time is valuable. Maintainable and reusable code is therefore cheaper. This may sound very reductionistic, but remember that operating in an economically efficient manner is the reason why we started automating things in the first place.

Acronym hell:

To the end of creating easily maintainable code we have come up with a shocking amount of tropes and acronyms: DRY, SOLID, SPOT, GRASP, KISS. Software theorists seem to really have a knack for catchy acronyms. We have made up at least a dozen of them. They signify very abstract ideas, design principles, and patterns that are supposed to help us achieve this goal of creating good code. Don’t get me wrong, these ideas are genuinely valuable. They have been carefully crafted by software developers with many years of experience with the best intentions in mind. They were not meant as absolute truths about how software should be designed, they were actually meant as heuristics useful when discussing different software architectures or decisions. From my experience, however, these principles and discussions have a certain nuance around them that is very alien to the analytical properties of the rest of the field.

The way code is structured, and the way we go about creating and structuring code is a highly subjective experience.

To us, code describes certain mathematical and analytical truths. But we fall into the trap of thinking that creating code must therefore also be an equally analytical process. But it’s not, and I see a lot of software developers struggling with this. There is more than one way to describe a logical predicate, or in our case an idea about functionality. Some descriptions communicate these ideas better than others. Communication is a multi-party task and what is obvious to me might not be clear to you. The way code is structured, and the way we go about creating and structuring code is a highly subjective experience. We can make analytical claims about existing code that are just undeniable logical tautologies, but we cannot make equally strong claims about the way the code is expressed. The problem is that these heuristics are discussed as if they are set in stone. As if all of these heuristics and tropes need to be applied.

As code is in the end always invisible, it is merely a means through which automation is achieved. Its inherent goodness doesn’t depend on whether all the software development tropes were applied or not. Must good code be DRY? Must it be SOLID? Must it adhere to all the holy design patterns? I think that most of these questions would need to be answered with an uncomfortable ‘no’. Uncomfortable because surely some of these principles have to be adhered to in some way, right? Imagine code that wouldn’t adhere to any principle and it would truly look disgusting and uninviting. But you would uncomfortably agree with me that they are not a necessity. You can imagine that in other ways code can be good.

Programming is an art:

I propose that the goal of easily creatable and maintainable code is achieved when the developer experience is maximized. The fact that Assembly is not a very common language to program in anymore is a testament to us continuously improving the experience of developing software. This goes two ways: we can both write and read code quicker. Our modern languages greatly improve code comprehension and quality of life. This is because common patterns and ideas could be encapsulated in a single command or syntax. Nowadays, we also heavily rely on domain-specific frameworks, IDE’s, version control and many more tools that are freely at our disposal and greatly increase our ability to develop software. As we are in the business of automating things, we naturally tend to make our own job as easy as possible as well. We understand that a better experience not only leads to a greater productivity when writing code, the code itself is also more likely to be of higher quality. This has been backed up by various studies that show happy developers solve problems faster and produce better code [1]. Interestingly enough, the developer experience that is supposed to improve their happiness is only very narrowly researched. Studies on developer experience mostly focus on ‘environmental factors’: IDE’s and other tools [2]. It suggests that our definition of developer experience is only related to external factors, and not the code itself. This almost makes it seem like it is just a matter of using the right tools. Want good code? Just use a good IDE and everything will work out! This cannot seem right…

The developer experience is first and foremost shaped by the actual code that the developer is interacting with. Contrary to the belief of some people, software development is not comparable to a production line. It is a process where we continuously interact with our code; comprehending, discovering, inventing, restructuring, testing and improving. To me, being a software developer sometimes feels more like being an artist. Starting from a clean slate we write expression after expression in order to articulate a complex and abstract idea into something functional. With that said, to think that we write code merely for a machine to understand is absurd to me. We never write code just for a machine. Our programs are a means to an end, and that end is usually valuable for humans.

def GCD (a, b): 
        if b == 0
            return a
        else 
            return GCD (b, a % b)

Even though it’s not optimal, Euclid’s algorithm is often hailed as a very eloquent and beautiful solution to the Greatest Common Divisor problem. But imagine this function not being called GCD and the impact this would have on your experience as a programmer trying to figure out what this function does.

I often compare knowing the basics of a programming language and being able to write some code to being able to form proper sentences in a real language. As we know, being able to form sentences is a very different skill from writing a book. A sentence communicates some information, but the meaning of the sentence is only derived from how the sentence structurally relates to the rest of the book. Just like with a sentence, a couple of lines of code can merely convey a simple idea and is rather trivial. The true challenge is structuring the entire project in order to express the grand idea effectively. A programmer may interact with a couple of lines of code, but they must be aware of the changes that these lines make in the context of the entire project.

Just like how a good novelist is able to affect the emotion of their reader with every deliberately written sentence, or how painters are able to evoke an aesthetic experience when someone looks at their work, software designers, architects, and developers should be aware that they are shaping the future experience of everyone interacting with their code. The process of software development is at all levels characterized by making decisions with various impacts. Every decision that is made about a project impacts the future experience of people when they also interact with that project. The code we work on and interact with itself determines the majority of our experience. The experience we have exercising our craft is only in part determined by the usage of the right tools.

Good software considers developer experience as fundamental:

Good code is said to be readable and consistent, these terms allude to the fact that good code is fundamentally code that has a pleasant experience when interacted with. Because that pleasant experience lets us be more efficient. We must see that it doesn’t matter how we structure our code as long as it satisfies a good developer experience. This makes the developer experience fundamental in software design. Readability and consistency for example are only some aspects of interaction. I can imagine very readable code while it would be atrocious to actually alter.

OPEN INPUT Employee.
    PERFORM UNTIL WS-EOF='Y'
        READ Employee INTO WS-Employee
        AT END MOVE 'Y' TO WS-EOF
        NOT AT END DISPLAY WS-Employee
        END-READ
    END-PERFORM.
CLOSE Employee.
STOP RUN.

COBOL is often considered to be one of the programming languages closest to English. This makes COBOL very readable but also bars it from having certain necessary syntactic sugar that modern languages have.

Programming is an experience. If the experience is good, the quality of the code and the productivity of the developer go up. If the experience is bad, the developer will more easily become tired, anxious, and frustrated. Therefore, writing good code is about writing code that will maximize the future experience of everyone that has to work with the project. The best and most interesting website designs don’t follow all the visual design principles. In the same way, good software doesn’t have to follow all the tropes and heuristics that we have come up with either. The best UX/UI designers in the world know all the rules of visual design and when to break them. Depending on the parameters of the project it is okay not to adhere to all the common principles as long as those decisions were made to improve the developer experience.

Good code doesn’t have to follow all the tropes and heuristics that we have come up with

Just like the visual design rules, knowing and applying software design principles and patterns is extremely important and will make you a better developer. But this is the easy part. Truly communicating abstract ideas is hard. So we should make every effort we can to make the experience of communicating these ideas as easy as possible. The experience of programming, of communicating abstract ideas, should be optimized to being almost frictionless.

And software development is a collaborative art:

The developer experience is the responsibility of everyone working on the project, at any level, at any time. To me, working on a software project is just a series of decisions at different levels. You have big decisions e.g. what language, framework or package to use. And you have micro decisions, like what to name a certain variable or which syntactic notation works best. Nevertheless, all these decisions impact the developer experience. Therefore, the developer experience is the responsibility of everyone working on the project at any level at any time.

Software development is thus a more holistic process. Thinking that managing a software team and making decisions about architecture are different things entirely is old-thinking. We know from studies [2] that the developer experience is affected by the usage of the right tooling. I have postulated that the communicative properties of the actual code itself has the most impact on developer experience. I am sure that there are even more factors that go into the developer experience like, for example, the organizational structure of the team or the way people within a team communicate. In the same way that DRY and SOLID try to improve the code quality, Agile and Scrum among others try to improve the software development process to the same end - I have to restrain myself not to rant about these principles as well, so I will leave that for a future article. However, we must see that the common goal of creating good - i.e. economic, efficient, thus maintainable - code is also positively affected by these organizational factors. All the decisions that are made on this level affect the developer experience. Keep that in mind.

Conclusion:

Software design doesn’t consider the experience of writing code as much as it should. We don’t think ahead. We have ideas about what good code is, what good software is. But this makes it sound like ‘good’ is a property of code. As if some code is better than other code for no other reason than certain ontological properties. A software project should be judged on how well it considers developer experience. That’s where the real value of code lies as it is just a medium for communication. The value of the ideas that software communicates are only as good as the code’s ability to communicate these ideas.

But contrary to most discussions about code, no reflection on code can be made with purely analytical and absolute truths. Discussing the communicative properties of code and its impact on developer experience is a very relative and nuanced topic. There is not one principle that will always decide on the ‘goodness’ of code. We need to see that writing code is not just a skill. We are not laborers, we are more like artisans or even artists. Creating software is a trait that requires deeper insights and understanding than the programming concepts that lie on the surface.

References:

[1] Graziotin, Daniel & Fagerholm, Fabian & Wang, Xiaofeng & Abrahamsson, Pekka. (2017). Unhappy Developers: Bad for Themselves, Bad for Process, and Bad for Software Product. 362-364. 10.1109/ICSE-C.2017.104.

[2] J. Morales, C. Rusu, F. Botella and D. Quiñones, "Programmer eXperience: A Systematic Literature Review," in IEEE Access, vol. 7, pp. 71079-71094, 2019, doi: 10.1109/ACCESS.2019.2920124.

This article was also published to dev.to and medium.com