What makes good code? (6/7)

João Bertolino
4 min readSep 28, 2020

--

Software Quality

So far we discussed how you write good code, but how to measure if your code is actually good? We have two ways to do that. One is by having a proof of correctness of an algorithm in your code. This is very important for some algorithms, but it’s hard to make a proof for every part of your software and you can still run into problems when you translate the model to the actual language. The other way is to run the code and look at what it outputs. You are making software, so why not make software that runs and tests for you.

Automated Tests are a huge topic in Software Engineering, but I think that the next simplification is valid: the more automated test cases are implemented, the more quality you have in your code. There are metrics of code coverage for how many parts of your code is being used in test cases and there are many types of tests: Unit Test, Integration Test, UI Test and so on. You will only know that you have code that works if you test it, so it is important to test at least the most crucial part of your code. There is an approach to design your code around Testing, Test-Driven Development, but that leads to some debate, because if you are iterating over your code in the beginning of development you have to do double the work, to update the test and the code itself.

Is it enough to have code that works in a lot of test cases? You can have two different codes that output the same result, but they might perform differently. When building software, we have two big constraints: processing power (time) and memory (space). To address that, we have Big O analysis for time and space. It basically analyzes the order of magnitude of how your code will scale the usage of resources based on the input. A classic example is sorting algorithms. The naivest way to implement sorting is bubble sort. It consists of comparing each element in the list with all the unsorted elements, resulting in the following number of comparisons:

(N²-N)/2 , where N is the number of elements in the list.

For Big O analysis, you only consider that higher order factor, in this case is the N squared, so it is represented by O(N²). In Big O analysis, we are not interested in calculating how many cycles of computing will be necessary to perform the algorithm, but rather the shape of the rate of growth. Bubble sort is a bad choice because we have other better options available in the literature for sorting. So, Big O is an important metric for algorithms performance, therefore code.

The image above shows us how different Big O functions grow over time. Consider a warehouse and you want to grab a specific item, but all the items are randomly placed on the shelves, so you will have to look at all items to find what you want. This search has O(N) time complexity. This is impractical in real life, so we use a lot of techniques to group and organize items, so it becomes easier to find them. Sorting and bucketing items are the most fundamental techniques and they share similarities with programming strategies to avoid bad time curves. Another important general strategy for reducing complexity is memoization, it is basically storing results to use later. We use that all the time in real life: when browsing the web, we save links, so we do not have to do the effort of searching it all over again. In computing, saving results will decrease time complexity and increase space complexity, but it is a great trade off in most cases.

Software development is a recent field in human history and despite how far we’ve come in so little time, many techniques are still evolving. John Romero, creator of the classic game DOOM, said that when they were making the game, they would share the files and the code of the game using floppy disks. Managing how you merge and maintain your code is not related to the quality of the code itself, but it’s a very important step to produce quality code. For that end, Version Control Systems (VCS) were built and there are a lot of architectures for that kind of systems, like Git, SVN, Perforce and Mercurial. It is crucial to manage your code with a versioning process and understand how to best use your VCS. Github provides hosting for software development and version control using Git and it’s a great source to read good open source code.

Now comes the interesting part, we can automate the software development to not only run the test, but to compile, to test and, in case of success, to deliver a running build in a test environment or, in case of test failure, to notify the team with the test result report. This is called Continuous Integration (CI). When you reach a release state of the software, you tag the version and the system deploys it for you, that’s called Continuous Deployment (CD). This requires some work to be accomplished and it depends on the technology you are using, but it is kind of the standard of making good software nowadays.

In the last section of this article, we are going to discuss how data influences your code.

--

--