Programming or Software Engineering?
Tags: softwareengineering, cleancode, programming
Published: 2022-10-01 10:33:00

> Software engineering is what happens to programming when you add time and other programmers. - Russ Cox

Coding something from scratch is (usually) easy. Getting things to work is (usually) easy. Things get complicated when you think about the past, the future and other people.

### Software Engineering deals with the challenges of

* Communication between people
* Communication over time
* Changing requirements
* Taming complexity

*Clean code is more about humans than its about tech.*

### Why invest in clean code?

- Minimizes time spend on reading and understanding
- Easier to grow in the future
- Less hunting for bugs
- Easier onboarding.
- => Messy code is **Technical debt**. You will pay for it down the road.

*Messy code has the uncanny ability to slow down any developer and make his work much harder*

### Bad Code smells

A [code smell](https://en.wikipedia.org/wiki/Code_smell) is any characteristic in the source code of a program that possibly indicates a deeper problem.

Here is a list of characteristics of a codebase that might lead you to think there is time to change:

- **Rigidity**. The software is difficult to change. A small change causes a cascade of subsequent changes.
- **Fragility**. The software breaks in many places due to a single change.
- **Immobility**. You cannot reuse parts of the code in other projects because of involved risks and high effort.
- **Opacity**. The code is hard to understand.
- **Needless Complexity**.
- **Needless Repetition**.

### Principles to prevent bad code

**Keep it simple, stupid (KISS)** and **Clear is better than clever.**

Writing clever code feels good. You achieved something. But more often than not, clever code increases the *opacity* of the code. If another developer has to stop at a piece of code and has to understand it because it is not communicating clearly what is going on, it either is a very complex matter or the code is more complex than necessary.

Lets take this snippet:

```typescript
['red', 'green', 'blue'].reduce(
  (myValue, color: string) => myValue.replace(color, ''),
  myValue,
)
```

What is it doing? It reduces the array containing colors by applying a function that is calling replace on myValue for the color it is iterating over and replaces the color with an empty string. So, after understanding that, what it is doing is removing all occurances of the colors in the array from myValue.

The following snippet is simpler and understood instantly. Yes, it is repeating code. So what? In this case, it does not matter.

```typescript
myValue.replace('red', '').replace('green', '').replace('blue', '');
```

**You aren’t gonna need it (YAGNI)**

Do not build things that you think you might need in the future. It overcomplicates the code and experience shows that often things will not be build in the future. Requirements and priorities change. The understanding of the problem will change. 

**Premature Optimization**

The same is true for optimization. Of course it is fine to optimizate code when it does not cost anything. If you know your code is faster if you use a Hashmap and access directly instead of using a List, do it. Writing it costs nothing. But starting out writing complicated solutions to optimize a request by 100ms is not the right way. Only optimize what is actually a problem and only as soon as you know it is a problem.

 **Don't repeat yourself (DRY)**, single source of truth. 

This is often misunderstood as not having the same lines of code in the program multiple times. *Do not repeat the same characters*. But this is actually not the right way to interpret the DRY principle. **Don't confuse syntactic and semantic dry-ness**.

DRY is about not repeating the same business logic in multiple places. There should be only one place in the program that describes how a business process is happening. This is about avoiding magic numbers, avoiding having the calculation of number of posts a user has in multiple places. The reason behind this is that when you have to change the program, you will probably forget to change all occurances of the logic and the number of posts will diverge.

If the code is simple it might be better for clarity to actually copy it. Do not overstructure things that don't matter.

**Practice consistency.**

Keep your code consistent. The way you code, the way things are structured helps you and other developers. Onboarding will be easier. Humans are great at extracting systematic structure but are really bad at remembering all the special cases.

**Keep the tests clean.**

*If you let the tests rot, then your code will rot too.*
Tests are code too. You will have to maintain them just like your production code, so treat them like production code. Introduce abstractions, stay DRY, have a high level of quality. Tests are often the best documentation you have, so clarity is extremly important. Make it very obvious what you are actually testing and hide the details. You will thank yourself soon. In my experience, most frustrations during development come from a bad test base.


**Prepare for change**

All software projects I worked on had in common that they never have been finished. There is always change involved. Therefor it is very important to *always ask how will this code behave if X changes (but keep YAGNI in mind)*. If you keep the code somewhat flexible without over-engineering, you will win the game of software development. This is more art then science though and comes with experience. Also, you will be wrong and that is fine!

--------

This article is extracted from a series of talks I gave.

{% embed https://www.slideshare.net/JaapGroeneveld2/software-engineering-principlespdf %}