Tools of the trade: What they don’t teach you in university

Developers around the world rely on various tools to make their life easier.
Sadly, most of the (essential) tools are either not taught or taught insufficiently in universities, leaving students lost, when facing real-life development problems.

Trying to deal with this and providing leads for new students, I wrote this.
In this short story, I’ll introduce you to three essential tools. Note, that the tools will be explained in-depth in following articles.


Imagine you were given an assignment by your professor, to write a fibonacci-calculator using C++.

The fibonacci-function is defined as follows:

render.png

“Easy!”, you think. Quickly you come up with the following solution:

(main.cpp)

#include <iostream>

int fib(int x) {
    if(x == 0)
      return 0;
    else if(x == 1)
      return 1;
    else
      return fib(x-1) + fib(x-2); 
}

int main() {
    std::cout << "fib(5) = " << fib(5) << std::endl;   
    return 0;
}

From your introductory classes you remember, that you have to compile the file using the following command:

g++ main.cpp -o fibonacci_calculator

As the assignment progresses, you get a message from the professor, saying that you are to place the function in a separate module. “Sure, can do”, you might think. So you end up with three files:

(fib.hpp)

#ifndef FIB_HPP
#define FIB_HPP

int fib(int x);

#endif  // FIB_HPP

(fib.cpp)

#include "fib.hpp"

int fib(int x) {
    if(x == 0)
        return 0;
    else if(x == 1)
        return 1;
    else 
        return fib(x - 1) + fib(x - 2);
}

(main.cpp)

#include <iostream>
#include "fib.hpp"

int main() {
    std::cout << "fib(5) = " << fib(5) << std::endl;
    return 0;
}

and you compile (& link) again:

g++ -c fib.cpp -o fib.o
g++ -c main.cpp -o main.o
g++ fib.o main.o -o fibonacci_calculator

After a while, the professor comes up with more and more minor requirements and you end up writing the compilation commands above over and over.
Annoyed by the repeated typing, you think to yourself: “Is there a way I can automate that?”

While you’re thinking about that, good guy Steve appears and, as if he could read your mind, he says:

Yes, there is. Applications that automate such tasks are called build systems. They come in different forms and vary in power. One popular build system, among many other, is called Ninja, which uses small files often referred to as buildscripts to describe the process of compiling and linking your project.
Having a buildscript, all you need to do, is to run the build system and it takes care of everything for you.

He quickly writes down a file on your PC and goes his merry ways. As he left, you take a look at what he wrote down:

cc = g++

rule compile
  command = $cc -c $in -o $out

rule link
  command = $cc $in -o $out

build fib.o: compile fib.cpp
build main.o: compile main.cpp
build fibonacci_calculator: link fib.o main.o

default fibonacci_calculator

# run "ninja" in your console

“Is this a buildscript, he was talking about?” You see the comment at the bottom and decide to give it a shot:

ninja
> [1/3] g++ -c fib.cpp -o fib.o
> [2/3] g++ -c main.cpp -o main.o
> [3/3] g++ fib.o main.o -o fibonacci_calc

“Nice! Looks like it compiles my project automatically.”

But luck wasn’t yours. Alas, while you went away to get a celebration coffee, the professor came up with yet another requirement: “Please make sure, that the results of the function are cached to avoid unnecessary calculations.”

You scratch your head. “I’ve never done such thing, this might takes some while.”

So you sit down and get to work. Hour after hour passed by, yet you struggle to figure it out. After few hours you decide you’ll rest and try again tomorrow. “I wish, I could roll back everything to where I started.”

Out of nowhere you hear a loud bang. Good guy Steve appeared out of nowhere with a time machine, pulls you into it and explains:

Get in, we’ll get it fixed in no time!
There is a tool called version control software. The most popular among them is git.
With git, you can create and manage backups easily as well as rollback to earlier versions.

As you hop out the time machine, you recognize the time. It’s exactly that the time, when you went out for your celebration coffee.

Steve swiftly gets to your PC, types into the console

git init
git add main.cpp fib.hpp fib.cpp build.ninja
git commit -m "Initial version."

and explains:

I created a repository. That’s what projects are called in git. And added a new version. Whenever you think you made progress, just add the changed files using git add and commit it with a message using git commit -m.

He drags you back into his time machine, starts it. As you arrive back into your time, he writes down something on a small note, hands it to you and disappears with his machine yet again.

You look at the note, recognize that it looks like one of these git-commands and decide to give a try. You type in:

git reset --hard

Alas, your work is reset to its state before the professor came in. This time you managed to fulfill the professors requirement just fine and finally go to rest.

The next day, you’re being pestered with yet another request: “Make sure to calculate the number iteratively instead of recursively.”

Sigh. You get to work and after a while you figure it out. Yet, you’re not content with your solution. “Is there a way to test automatically whether the new solution is correct?”

Yet again, good guy Steve appears out of nowhere.

Yep, it’s called unit testing. With unit tests you can check whether a particular part of your project, hence the word unit, works as intended. Generally it’s advisable to execute the function for the corner cases, like zero and one in your case, as well as for few selected values. If the values returned are what you expected, then you can assume everything works fine.

Yet again, he starts typing out something on your PC. This time it looks like a

C++ file.

#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include "fib.hpp"

TEST_CASE("Fibonacci is computed as expected", "[fibonacci]") {
    SECTION("corner cases") {
        REQUIRE(fib(0) == 0);
        REQUIRE(fib(1) == 1);
    }

    SECTION("general cases") {
        REQUIRE(fib(2) == 1);
        REQUIRE(fib(3) == 2);
        REQUIRE(fib(4) == 3);
        REQUIRE(fib(5) == 5);
        REQUIRE(fib(6) == 8);
        REQUIRE(fib(7) == 13); 
    }
}

There are many testing frameworks out there, helping you create tests quickly. For this one, I used a popular one Catch2, which just happened to be installed on your system.
Unit tests are often just applications and are compiled as such.

Disbelieving, that such things exist, you take a look. Indeed, you got a new application test_fibonacci. You run it and, alas, you’re greeted with a message: “8 Tests passed. 0 failed.”

At this point you realize, you’re done with the project and you can finally relax.


You came this far! Great 👍.

In the next articles, I’ll go into depth about

with the first one being released on the 20th of September.

In the meanwhile, here are some tools, which you can checkout:

So, stay tuned!

If you enjoyed this article, and want to support me, feel free to share this on twitter.

 
2
Kudos
 
2
Kudos