DEV Community


Posted on

How to write 'unbuggy' code? - What I have learned from the malloc lab


Recently I have just finished one of my personal self-studies, the malloc lab. It is about how to implement the functions malloc and free so that one can have a deeper understanding of how a computer does its memory management. I guess it took more than 50 hours for me to 'finish' this lab(by which I mean that I have managed to implement a seglist data structure and passed all the validity tests). And most of that time has been spent on debugging.

Three Principles

But why did it take so much time to debug? During those painful times, I have realized several important principles one should keep, in order to reduce debugging time.

First. (System)programming is really hard.

Unlike other managed languages like JavaScript or Python, if you are programming in C/C++, you must make sure that every pointer operation is decent. And this is really hard. Even a simple typing mistake can lead to a huge error. *(size_t*) and (size_t*) are totally different.

Moreover, one cannot really be sure where the error comes from. Those kinds of languages like JS and Python would tell you where the error has occurred and what is the source of the matter. On the other hand, in C/C++ you'll only get a segmentation fault. In my lab work, this was mainly due to wrong access to a memory location. But even if you realize that you are not sure what is the source of the problem. It could be as little as a typing mistake(like missing an asterisk), but also as big as the overall design problem.

It might sound weird to tell that one thing is hard could be a principle. But bear this in mind: C/C++, or any other memory-related system programming is hard, and you should be vigilant while doing your work.

Second. You need to have a good initial design of your product.

Data structures, algorithms, macros, global variables - every element of your code matters. One small change could make a huge difference in the output, so you should be careful when designing your code.

A misleading design could be a source of relentless pain. Your code is wrong, but you're not sure where the error comes from, because you're doing memory-related programming. Luckily it might be that your code runs smoothly without any warning sign, but the bugs insinuate themselves in the code and await further important testings. So from the beginning, you should have a good design of your code.

Third. Do refactoring right here, right now.

In a lot of cases, bugs occur in a part that you don't think that it is problematic. It is a perfect code, with a perfect design with no syntactic error. But as a matter of fact, it is buggy.

From my experience, I can surely tell that you can get rid of many of these cases by keeping the DRY(Do not Repeat Yourself) principle. If you repeat a single functionality over a whole product, you have to fix it by checking every chunk with Ctrl + F. But why should you? Separate that functionality as a single function or a method, or even a class. Then when an error comes in, you simply need to check that portion rather than the entire product.

Fourth. Real-time documentation is necessary.

Finally, I should mention this. You are a human and you are not perfect. That means that you should give some chance to future-yourself to catch up with your current work. Documentation is not only for other coworkers to communicate but also a way to communicate with yourself as well.

Especially when it comes to complicated works like SW development, you MUST do documentation whenever you think it is necessary. Postponing documentation sets up caveats in front of you, and sometimes they could be huge.

But what I mean by "documentation" is not something like jotting down every detail of your work. Rather it could be a small single line of comment within your code. The important thing is timing. it is like a successful person always does one's memo. A brilliant idea suddenly comes into your mind at a moment and you should keep it.

Last Word

We as humans are not perfect and bugs are an essential part of SW development works. Debugging is painful and time-consuming work. We have to organize our way of doing work to minimize bugs and debugging times.

There are many other good practices - TDD, clean code, version control, to name a few. SW development work is hard(especially memory-related work) and we need to keep in mind those principles and practices while working, for the sake of other colleagues and ourselves.

Discussion (0)