Friday, 2 November 2018

WebCalc iteration 4 - fixes only


Welcome to the fourth iteration of WebCalc implementation. Previously I added multiplication and division as operations supported by my WebCalc. Especially the latter one forced me to add and change a few things in the code. By doing so I think I've made a mistake, that I'll fix now.

The problem was to make Calculator stateful, it now remembers maxFractionDigits. If one user would set maxFractionDigits, all others would see that changed too. That's actually a serious bug, I'm excused just for now and just because my application doesn't know about users or sessions yet and have no tests verifying correct behaviour. But merely making such service a stateful one can also be perceived as an issue. No matter why I'll fix it now.

Because I'm using TDD, I need a test verifying the presence of my bug. Here it is:


It works, it is failing because of setting something in one session affects the other. It also looks lengthy, I'll cut it a bit to make it more readable, like so:


Still works, but I think it more says about what I want than how to do it, that's good.

Having proven I have indeed a problem I can try to solve it. My idea is: I'll store maxFractionDigits in HTTP session and on every call to eval function I'll in this parameter explicitly. Now my controller looks like this:


I've badly broken my Calculator module API, it will cost me a bit of time to fix it. First, I'll add this parameter to eval function but will not use it just yet.


TDD outside-in way, I'll fix the tests first. Tests for the division are easy, because they have maxFractionDigits provided explicitly, but all other tests? I need a default value and I need to put it somewhere. Calculator class would probably be the best place to keep it, as it is doing all the calculations. As for value, I'd probably need to ask my users or product owner. Because I have none, I'd assume 2. So my tests now look like this:


Most of my division tests are now broken, as well as all REST tests. Time to fix this. It's actually not that hard. I just delete the class field and start using the value provided to the eval function itself. The code now looks like this:


That fixes all unit tests and my newest REST test. Unfortunately, my previous REST tests are now failing because of NullPointerException. Indeed, my session doesn't have "maxFractionDigits" parameter set by default. The fix is quite simple:


But that fixes only one of my tests, the other one with setting maxFractionDigits is still red. Indeed, it doesn't keep track of the session. This time it's the test that needs fixing:


Phew, back to all green, unit and REST tests. Is everything good? No, I've noticed a race condition in Calculator. This class is still stateful, because of formatter. On every eval function call, I'm changing its state. With bad luck, two sessions will interfere with each other. The solution is to get a new formatter and set it up every time it's used. This time I'll not TTD-drive it, I honestly don't know how, or even if it is possible. I could try to create a lot of sessions and execute different calculation requests in parallel, but even that doesn't guarantee I'd trigger the problem. Anyway, as I'm already touching this area, I'm also extracting all formatting activities to a separate method, like this:


There's yet another thing I've noticed. None of my test cases is using numbers with digits after the decimal point as an input. For completeness sake, but also to check for formatting issues, I'm adding a few test cases, like so:


And, not really surprising, I have a problem. I am formatting my output, but I left input with default settings. Again, time for fixes. It looks like NumberFormat is not enough, I'd need a DecimalFormat. Luckily, I can also use DecimalFormat for formatting my output. That way input and output will be in sync. I end up with this:


This starts to get complicated. I also have some duplication, I'm creating a formatter in two different methods, but also every single time I need it, let's get rid of it.


Better. This ParseException, that I need to handle explicitly, bothers me a bit, but I'll need to add some proper error handling sooner or later, not now though.

One more thing to verify. The fact, that I'm limiting my output to a specific number of fraction digits doesn't mean, that I should also be cutting my input. Example, I'm still using my default 2 fraction digits of the result and the calculation to do is to multiply 3,333 by 4,444. If I just multiply and not limit the result, I'll get 14,811852. When I round it to 2 fraction digits I get 14,81. But if I'd first round my input to 3,33 and 4,44 respectively, then my results would be 14,7852 and 14,79 before and after rounding. So rounding or not my input does affect the final result and I don't want the input to be rounded. But this test case will verify that. Test:


Luckily my code is correct and all tests are green.

That's a lot of fixes or things I forgot to do earlier, even for such a simple thing like a calculator. No wonder that software we're writing has so many bugs. It is then even more crucial to be careful, think constantly about what can go wrong and then secure yourself with tests.

OK, it doesn't seem like I could be adding anything new to my application in this iteration, so at least I'll upgrade a few things. Recently stable Spring Boot version 2.1.0, Java 11 were published, also Gradle released version 5.0-RC1 with Java 11 support. I'll start with last one:


All tests still working and green. Now Java:


Still no issues, time for Spring Boot. This one also includes syncing of library versions:


Tests still running and green. I'm still annoyed by the fact, that I cannot use dependency management from Spring Boot in my Calculator module, I'm getting very weird compilation errors. This time I think I'll try to deep dive into this because I'm probably doing something wrong. If not, I'll file a bug.

That part was tough, I achieved not much progress, only in terms of having fewer issues in the code. Hopefully, next time will be better and I'll actually get to the part, where multiple calculations could be combined together. See you next time!

Wednesday, 10 October 2018

WebCalc iteration 3 - formatting and cleanup in calculator module

Welcome to the third iteration of WebCalc implementation. Previously I managed to get only basic operations working, namely addition and subtraction. This time I want to go further and add multiplication and division. Whereas multiplication should be pretty straightforward, I'm expecting issues with division. Once I get this things working, I'll see if I can improve design of calculator itself and the tests. To IDE then.

Multiplication is, indeed, straightforward. I copy subtraction test (which still bothers me, but I don't see a better solution yet) and modify it accordingly, like so:


Implementation is a tiny bit more complicated, because I need to replace an if there with something else. Well, I could use 'else if', but instead I'll use a switch over strings, never done that before honestly. Everything else is obvious:


I'm adding a few more test cases, just for completeness sake.


No surprises here, implementation is correct.

Division starts fairly simple. Yet another copy of tests and I have:


So far the implementation can look like this:


Works for now. Now it will get trickier, because I want to leave a world of integers. I'm adding a simple test case:


It failed because of decimal point. I'm from Poland, currently living in Germany, and in both those countries we're using coma as a decimal point, not a dot. Java, when converting BigDecimals to strings, is always using dot. If I want to get a coma in string representation, I need to format the numbers using NumberFormat, like so:


Now I have a coma. Next problem to solve is rounding. Division is a first operation, that can produce infinite expansion, but I need a finite number of digits to return. I don't know if that's a good idea, but I'll add to the Calculator a possibility of setting max fraction digits.

Digression, in hindsight, it's a bad idea and I'll have to fix it later, in the beginning of 4th iteration probably. Although I've found it out after writing the code and during writing this article, I decided not to go back, fix it immediately and hide my failure from everybody. It happens to me all the time, and not only to me. We're all making mistakes, we just need to reflect on them and learn from them. It is a very important part of software engineering.

Back to code, merely adding a test case will not be enough this time, I'll need to change a bit more. This is the moment, where all test methods stop looking exactly the same way, so making a copy for a division was a good decision. Now my test looks like this:


Calculator needs to get its setMaxFractionDigits:


So far it works. As usual I'm adding a few test cases to find out if I've covered all cases:


Funny enough I didn't. Although I was limiting max fraction digits in the division, but printing number out, just by accident, was also using maximum 2 fraction digits. In the end I didn't notice, that I've missed something. When I asked for higher (or lower) precision, I didn't get what I wanted. Fix is simple:


I'm looking at the Calculator and I think that eval method has grown beyond my liking. Especially this big switch is bothering me. Luckily Java has something like BinaryOperator, that I can use, so I'm extracting a method finding out what kind of function needs to be applied to two values.


I think the Calculator itself is now more complete, I don't yet see any applicable improvements. Parsing string looks like a candidate, but it would change once I start dealing with more than one operation on two numbers, so I'm leaving it like it is. Also looking at calculator tests I still cannot figure out if I should merge adding, subtracting and multiplicating together. They seem very similar, but operations are different after all. I'll probably stop tormenting myself with that and leave it be. I can always return here later on and merge if that would make sense.

It's time to see if something needs to be changed from REST interface perspective. Indeed, setting max fraction digits is not handled at all, and I should probably also test division from outside, as it is quite different from all other operations implemented so far. My new test hitting the application from outside looks like this:


Fixing the controller is straightforward:


That will be all this time. Next time I'll start by fixing handling of max fraction digits. I'll also stick to Calculator itself and add a possibility of doing some more complex calculations. See you next time!

Friday, 21 September 2018

WebCalc iteration 2 - actual calculations and modules separation

Welcome to the second iteration of WebCalc implementation. Last time I managed only to get a basic construct working and only in a very crud way. Always returning "3" from a controller is hardly a proper solution. This time I'll separate app module from calculation one and then I'll start digging into actual calculations.

But first, looking at Gradle files I've noticed a few unnecessary things. One thing is, that I'm specifying explicit versions for JUnit and REST-Assured, which, having Spring Boot, is not necessary. Another is, that I'm importing snapshots repositories I don't need. Yet another, I'm using "compile" instead of "implementation" when specifying dependencies, where the former is not exactly deprecated, but the latter is preferred. And, at last, just by copy-pasting last time, I have a mix of single and double quotes, so I'm changing all to double ones. See commit 60acf63. (May I express here my dislike to how many different syntaxes are allowed to do one thing? I didn't even start properly and already have a mess).

Having that aside I can focus again on the project. What I want to do is to move calculations from controller to calculator. That one doesn't exist, so I'll create it, starting of course with a test. Crazy enough the API will be very simple, take a string in, return a string, so all this parsing will be done on calculator side, not in controller. Makes sense, controller should only be responsible for handling the web part, so HTTP, declaring content type, etc. Parsing input belongs to calculator. So, the test:


To make it green I need an implementation. It cannot be any simpler than:


Now I need to call the calculator from controller, again, simple:


A bit crud, but the tests work. Talking about tests, it seems, that WebCalcApplicationTests, which was generated automatically by Spring Initializr, is obsolete. It makes sure, that ApplicationContext is able to start, but my RestApiTest is also verifying that, I need a full working application there. It also takes some time to execute which I just noticed. I can delete WebCalcApplicationTests.

Controller needs to be cleaned up. First, I create a calculator field and initialise it in constructor:


Everything still works, but it's still not perfect, I don't want my controller to know how to create a calculator. I'm going to do it Spring way, create it as a bean somewhere in Spring configuration and use constructor injection, like so:


OK, I have now three classes, that belong to different modules, business logic, web and app. Time for some Gradle subprojects.

First step is quite big in terms of commit size, but provides little more than setting up the stage. It is required though. I'm creating a subproject in Gradle called "app" and I'm moving everything in there. This module, in future, will hold only classes responsible for setting up everything, starting Spring, instantiating context, etc. See commit 03e5db0.

Now things get more complex, as I want to extract a "calculator" module. That one will only have classes responsible for calculations and will be free of any framework dependencies, like Spring. It will also be compiled first. While doing that I faced some serious problems with, most likely, dependency management Gradle plugin from Spring Boot. Whenever I was trying to use it in calculator module, my tests in app module were not seeing classes from calculator. Playing around with Java, Gradle and Spring Boot versions didn't seem to make my situation better. But, as you might have noticed, I was "inviting" Spring Boot project into my calculation module. I'm not going to pull in Spring itself, I just wanted to get the same version of JUnit and AssertJ everywhere, which this plugin could ensure. It didn't work (or I'm too stupid to get it working correctly), so I had to go back to manually setting versions. Long story short: see commit 4601920.

Enough with Gradle, right now the structure is better. I could extract also the web module, but I don't need it just yet, I only wanted to have calculator separated, because that's where I'd focus next. First thing I want to do is to extend my test to be parametrised, so that I can easily add more test cases, like so:


Now I'm adding a second test case, that would force me to stop blindly returning "3" from the calculator:


Fixing this is quite easy, although I need to deal with parsing strings. At some later point in time I'll probably separate parsing from calculations, but I don't know yet in which direction the code will go, so I'm not doing it now.


As you can see, I'm using BigDecimals, although I don't need them just yet. It's a conscious decision, I don't want to rewrite all of the code once I reach a point, where I'd need some floating point operations.

I'm also adding a few test cases, just to be sure, that my adding also works for bigger numbers, as well as negative ones.


I used "obvious implementation" in the code, so no surprises here, all works.

I'm going to extract calculator as a field in the test, it will help me soon.


Now I can add a new operation to calculator: subtraction. As usual, I'm starting with test:


Implementation is quite obvious if not a bit dirty:


Again, I'm adding a few more test cases to also test negative and longer numbers.


So far so good. Am I sure? Not really! I was so into calculator module itself, that I didn't notice my integration test stopped working. But that's easy to fix:


And that would be all this time. I definitely have a messy implementation of calculator itself, that I'd need to deal with soon. After I add a few more operations, and maybe partial support for floating point operations, in next iteration, maybe it will be more clear how to clean it up. Also, the tests for addition and subtraction look worryingly similar, for multiplication and division they would also look the same. But here, although it's an obvious duplication I don't want to merge them, because they're theoretically testing different operations. Or maybe I should? I'll see next time. See you later!

Wednesday, 5 September 2018

WebCalc iteration 1 - setting up with one test

Welcome to the first iteration of WebCalc implementation. Although in the end I'll try to have something "business" related, I guess most of the time I'll spend wiring things up. To the keyboard then.

Goal


I want to have a very first and simple test working: adding 1 to 2. It will go to the REST interface so that it would force me to wire up everything to get an application available over HTTP/2. This would clearly be an integration test. Below that I'll have my unit tests.

A bit of infrastructure


The easiest way to start a Spring Boot project is to visit Spring Initializr. I chose a Gradle project with the newest version of Spring Boot, Java 10 and Reactive Web. This should get me started simple. See commit fb831f9.

One thing, that I need to fix almost immediately, was removing JUnit 4 and plugging in JUnit 5. Nothing difficult, but it would be nicer to have a boot started with JUnit 5 already. So build.gradle changes:

Now I need to change the test, because it's using old infrastructure.


First test


Now I can write my first test. As I don't have anything so far, I need to start completely from outside, so through my REST interface (idea of a walking skeleton). I also need to decide how this interface would look like. Let's say, that my endpoint will be responding to GET requests on URL "/eval". Let's also say, that, to keep it simple, I'll not be using JSON, XML or anything, I'll be using good old "text/plain". Just for the fun of it, and to avoid weird parsing issues, I'll be expecting my input to be using reverse polish notation. Last decision: to actually test my application from outside I'll be using REST Assured.

OK, from now on, there should be more coding and less talking. First, I need to import REST Assured:


I can finally write my first test:


It fails miserably, as expected. After reading Spring documentation a bit I can see, that using WebFlux is probably an overkill, so I'm going back and replacing it with good old SpringMVC. As the most basic things like controllers are common to both stacks, if I were to switch later on to WebFlux, it would probably take me very little time.


If I take a look at test results, the problem there is, there's nobody listening on localhost:8080.
java.net.ConnectException: Connection refused (Connection refused)
As the application actually didn't even start, it's not a wonder. Let's fix that.


Application was started, it listens on port 8080, but nobody responds to request to "/eval".
java.lang.AssertionError: 1 expectation failed.
Response body doesn't match expectation.
Expected: "3"
  Actual: {"timestamp":"2018-09-04T06:44:17.247+0000","status":404,
     "error":"Not Found","message":"No message available","path":"/eval"}
I need a controller.


Now it looks far better, I got an answer, but not the correct one. That's easy.


Tada! First test green.

That's it this time, next time I'll go deeper into the application and separate web part from calculations. See you soon!

Tuesday, 4 September 2018

Project WebCalc - motivation and plan

My previous post were rather theoretical, a lot of philosophy, very little code. This time I'll do almost the opposite, I'll be actually writing a little system before your eyes, so there will be a lot of code. I will be referring to some concepts I was writing about previously, but this time I'll not be discussing them, just applying.

Motivation


There are many reasons I want to do this:
  1. I want to really show, that everything I was talking about (plus other things I didn't mention so far) are actually doable. As Linus Torvalds puts it: "Talk is cheap, show me the code".
  2. There are multiple technologies, that I never had a chance to actually try out like Java above 8 including modules, JUnit 5, Spring 5 with reactive web stack and HTTP/2 or Kafka.
  3. I've known theoretically both hexagonal architecture and domain driven design and I'd like to apply them somewhere.
  4. I'd like to find out if things, that I was doing so far in a specific way, could be done better with design patterns. I have no clue if I'll find such functionalities, but I'll try to keep my eyes open.
  5. When working with Spring applications, it's very easy to let Spring go too deep into the application itself. I think I know what Uncle Bob means, when he talks about "main partition", but I want to finally write an app this way to prove, that it's actually possible. Also, my wife is now struggling with testing of a legacy application that's using Spring Security, so I also want to find out how to test such applications properly.
  6. Whenever I'm looking for some examples of how to use something, they're very simple, covering only the basics, and, quite often, providing very little value, especially when I'm struggling with putting together two different technologies. So I thought I'll create a sample project putting together a few things, show how they work together (or against each other) in a much bigger and comprehensive "example". I will also be "recording" changes to the code in git, so you can follow the commits to see how the system was evolving.
  7. I've seen video series from Robert C. Martin and Sandro Mancuso "London vs. Chicago" and, honestly, I see some serious flaws in both their approaches (which they both also acknowledge). London school of TDD (outside-in with a lot of mocking) seems to me like it would later on prevent any refactoring, because every interaction between components is mocked and thus fixed. Chicago school of TDD (inside-out) seems to be avoiding this problem, but then the amount of speculation about what might come worries me. By the way, both of them agree to those points and provide ways of mitigating those issues. But, having watched an excellent video from Ian Cooper "TDD, where did it all go wrong", I'd like to see how Kent Beck's style TDD can this be done in practise and if this approach would lead to a different code (and issues most likely).

The app itself


As this is actually the least important thing in my endeavour, I'll keep it simple. It will be a calculator with REST interface. It will support a few basic operations like addition or multiplication, maybe a few standard functions like trigonometry, not much. It will be available to only registered users as a paid service, so it will need to have things like authentication, user management and billing. Users might also belong to a bigger organisation like research institute. That would allow us to bill the organisations, not individuals.

And that's it. Hopefully this will already enable me to show/test/play around with things I mentioned above. If not I'll be either adding new features, or I'll be dropping some ideas. I guess it will depend on time and how much I really want to deal with particular topic. Hopefully, given big enough audience, you could also try to convince me to add or remove something. I cannot tell anything right now for sure, nor I want to promise anything.

What's not planned


As mentioned above, the only interface I'm planning right now is REST, any other GUI is a far bigger topic for me to include in here. I'm mostly a backend developer, just to try to catch up with frontend I would probably be creating a similar project to this one, but focused on Web UI. Maybe I'd take this application as a starting point, but that's currently speculation on my side.

Deployment is also outside of scope. The app will be just a standalone JAR, most likely with only an in-memory DB, if necessary. I'm not expecting any need for something like Docker, Kubernetes or anything "cloudy".

I'm not currently planning it, but maybe I'll change my mind later on: operations and monitoring. Though I'd like to learn Spring Actuator more, but I'm not sure this is the right time and place. If I find a good use case for it, I'll not be thinking too long before including it in here though.

High level architecture


Although TDD should help me get a good architecture of the system, I should have an idea of how it should look like. As mentioned already, I'll be using hexagonal architecture and I expect around 5 modules to appear:
  • "business logic" so calculator itself,
  • REST interface,
  • user management,
  • billing,
  • app.
Last one might require some explanation. The concept comes from Robert C. Martin, a.k.a. Uncle Bob, and it's described in his "Clean Code" book. General idea is, that each other module doesn't know how to actually start, where to get its dependencies, etc. It's the role of "main" module (or, as Robert calls it, partition) to be able to wire up and start everything. This should be the only place where Spring lives. Each module will also be a Java module, so I will be able to enforce some additional restrictions as to code visibility.

Having modules clearly separated from each other, I can apply TDD to each one and test them only through their APIs. I'll treat each module as a separate unit, just like Kent Beck intended. Most of my tests will be going for those module/unit APIs, but I'll also have a few integration tests, starting with a REST call and going through the whole system.

According to DDD (domain driven design) every module might/should have it's own data model, so please not be surprised if I find myself having, say, at least two different concept of users or accounts, one for purpose of authentication/authorisation, one for billing and maybe yet another in calculator module.

There's a bit of a speculation above, I don't know how many modules I'll end up with. I also don't know how many domain models I'll have in the end, but most likely it will equal the number of modules. All this I expect to emerge by itself from the code.

One more thing, even though I'll have multiple modules, I will not be creating microservices. I'm not too fond of them, because quite often they create much more problems, than they actually solve. Plus this project is far too small to get any benefit from such architecture. But, having separate modules I could easily go that way if I needed to.

What can you expect


I'll try to post regularly. Current plan is, that each post will cover one "tomato", so 20 minutes of working with code. I'll show you the code and changes I'm introducing. I'll also try to explain my thinking, why am I doing the things I'm doing, and why in such way. Like mentioned before, I'll not be going too deep into explanations, just referring to a concept.

You can also follow the code on GitHub, where I'll be pushing all the changes in small chunks.

So far I'm not planning any videos or screen casts, but if need be, I'll think about them.

Without further ado...


That's about it for an introduction. In next part I'll get my hands dirty by starting actual implementation. Hope to see you there!

Friday, 22 June 2018

Understanding decomposed


I previously wrote about simplicity and how it helps to understand software code. In that post I already mentioned the usage of concepts like set theory. I’d like to expand on this and show how to boost readability of code.

Despite what people might think, our main purpose as developers is not writing software, but solving problems. Code is just a means, not the goal. Nobody demands software just for the sake of it from a developer. Applications need to solve whatever problems our customers need to have solved. This point of view on why we are here also changes what software is. It ceases to be a merely different formulation of a solution that is specified somewhere, it is the solution. But this requires us to think differently about what it is we are doing, and how we’re doing it.

Code is the ultimate truth, as they say. After all, this is what is executed in production, not some written specification, diagrams, JIRA tickets, or the ideas we’re keeping in our heads. The problem is, that if the code is the solution, then there are a few groups of people that need to understand it. The first one is developers, after all we’re closest to it, we’re writing it, it’s our bread and butter, our life. The second group is the stakeholders or customers, who are defining how the systems should behave. Maybe some other groups, like operations, are also interested to understand how the system will behave, or with what other systems it interacts.

Let’s do a small experiment. Below is a piece of code. Please take a look at this and try to name the algorithm that is implemented here.

int n = arr.length;
int temp = 0;
for (int i = 0; i < n; i++) {
    for (int j = 1; j < (n - i); j++) {
        if (arr[j - 1] > arr[j]) {
            temp = arr[j - 1];
            arr[j - 1] = arr[j];
            arr[j] = temp;
        }
    }
}

It’s bubble sort, but it probably took you a few seconds to find out. If I just wrote `bubbleSort(arr)`, you’d know immediately what it does, how it's done, and a few other properties of the algorithm, like it's terrible performance for bigger arrays. The only trick I used was to name this piece of code, and this name refers to something you already know. If you don’t, it’s very easy to find out.

My point is, that by using known concepts we can make the code shorter and more understandable. This piece of code is 11 lines long, merely calling a function takes just one line. Of course, those 11 lines need to be written somewhere, but we can hide them deeper in our code, outside of the part where the “business logic” lives.

Those concepts can be anything. I mentioned a pretty obvious one, making elements of a collection ordered in some way, it’s called sorting, everybody knows it. Another example could be set theory with such operations like intersection, set difference or Cartesian product. After all, our applications are about data processing, and it's never about one "data". Yet another example of such concept could be design patterns, which are re-usable solutions to well understood problems. Once a developer hears about, for instance, a decorator pattern, he or she should immediately understand what to expect.

There's a really nice tweet from Mario Fusco:
Although it's a bit biased towards the functional way, and imperative code can definitely be improved (see discussion below the tweet), it clearly shows some benefits of using pre-existing ideas, monadic function composition in this case. Knowledge of such a technique, coming from the functional world and now being more and more adopted in OOP world, enables not only a better separation of concerns, but also more descriptive code. I'd argue, that the functional code says more what it does, imperative code is more about how to achieve it. Because of that, the functional code is more readable and understandable; it conveys intention. And it's just an example, I'm not trying to say, that functional programming is always or usually better than object oriented or procedural approach. But because in functional world certain mathematical abstracts are much more present or natural, also the code can be far easier expressed in terms of those abstractions.

Why is it so important to go for known things? Because they tend to "disappear" from the sight and leave more space for other, usually more important matters. Once we can refer to some external knowledge, our brains don't need to worry about that part any more. If I know what "intersection" from set theory means, then understanding `a.intersect(b);` is trivial. I don't even see the dot, the semicolon and the brackets any more. If I wrote `a.commonElements(b);`, I'd probably force myself and others to think about or find out in the code what is meant by `commonElements`. It would be one more thing to keep in my head, in my working memory.

This memory is however very small. It can keep approximately 7 "things" at the same time. Once we exceed our own limit, we're loosing the whole picture, we cannot comprehend the whole problem as one any more (by the way, this is also the moment where bugs start to creep into our code). If we refer to something we already know, then those concepts don't need to "take up space" in our working memory, so it's easier and faster to reason about the code.

A different aspect of understanding has to do with the language we're using. The software we're writing is a type of a mental model. Those models try to reflect real life as much as possible or necessary. They can also have theories built around them helping us deal with real life or decide what to do. Those models and our software should be as close as possible to real life models to reduce friction between them. Any differences are bug breeding grounds, and very time consuming to work with. Every time we see parts of the code, that show inconsistencies, we need to think about whether the code indeed reflects reality, or whether it looks like it looks, because we were unable to express reality in a better way.

This whole idea plays very well with ubiquitous language, an integral part of Domain Driven Design. It states, that there should be only one common language used to talk about the problem we're trying to solve, no matter who's talking to whom, developers, testers, business people, and also in the code. It makes sense; why would we want to "translate" between code, documentation and spoken language, after all, we're talking about the same things. In such translations we'd be loosing important details, and it also takes time and effort.

If such a language doesn't exist yet, we should create it. Or rather, like agile or extreme programming proposes, use metaphors. That way, although there's no language specific to the kind of problem we're trying to solve, there is a similar concept from which we then can borrow. This will also help in communication between people; instead of describing terms every time we need to, or giving them some artificial names, we can use terms from this other domain. Their power is, that they already have a meaning in the context we're interested in. It will also greatly speed up bringing new people to the project or talking about the project outside.

Code written using ubiquitous language or metaphors will also reveal its intent much quicker. It's a very important property of a simple design. Such design leads to quicker software development and only implementing what is actually needed. If we can split our big problem into smaller ones and properly separate the concerns, we have higher chances of being able to use ubiquitous language directly in the code, thus making it more understandable. Our code should be talking more about the actual problem it's trying to solve, than any technical solution it uses, like libraries, frameworks or databases.

This also might have the additional benefit of not having to write code at all. Chances are, that for any problem that is not core and unique to our business, someone already solved it, and there is a library available. If we use this library, we'll save ourselves the time writing and maintaining it, and we'll be able to focus more on important matters. It will, again, make the code more understandable, because there will be less code to understand. We should also remember, that our task is to solve problems, not to write code, and we should only work on something that differentiates our companies from the competition. This is where profit is generated, commodity code has already been written, all companies can get it, so there's no real advantage here.

As you can clearly see by the sheer amount of topics and concepts I mentioned in this post, it's not so easy to keep our code understandable. And I didn't even mention all of them. It also means, that we can make our code difficult to read in so many ways. But I believe, that it is in our common goal to make our code more readable and understandable. This not only makes working with such code easier, but helps us to deliver value faster.

Happy coding!

Note, this article was originally posted on INNOQ blog.