The Pragmatic Programmer EP.5 — Imperfect Software

Natnicha R.
CodeX
Published in
4 min readMay 10, 2022

Because we will never be able to create flawless software. As a result, we employ the following techniques to ensure the high quality of the software you will have.

Design by Contract (DbC)

Photo by Pixabay on Pixels

A contract is a thing that will be made to be an agreement between two or more people, especially in case business dealing. One of them will be a client who hires another person known as a supplier to do something. Turning onto the applying contract to our code, before creating a routine, we have to declare the contract including 3 main parts as Mayer’s described:

  1. Pre-conditions: A condition that must be true to enter the routine.
  2. Post-conditions: A condition that must be true after entering the routine.
  3. Class invariants: A statement that must be always true from the perspective of a caller.

If you promise to call me with a satisfactory precondition, I will deliver the final state to you with a please postcondition.

Thanks to the availability of knowledge material at win.tue.nl for the below sample:

Obligations                        Benefits
--------------------------------------------------------------------
Client Pay entire cost for one month in Enjoy a low-cost
advance. Bring only limited hassle-free all
baggage and valid passports and expenses paid vacation.
visas, etc. Arrive at the airport
for two hours before the flight
leaves.

Supplier Locate, select and book airlines Make profit on sale
carrier, auto rental, hotel, etc. even if client does not
within required time frame and show up at the airport
budget. on time and properly
equipped. May even keep
possible partial refund
from hotel etc. in such
cases.

Here is an example of applying DbC in an Eiffel language:

Thanks to win.tue.nl

Design by Contract (DbC) VS Test-Driven Development (TDD)

  1. DbC requires mocking whereas TDD does.
  2. DbC defines all success and failed cases whereas TDD aims to test a specific case.
  3. TDD executes only testing time whereas DbC is forever that includes design, development, deployment, and maintenance phases.

Error Handling

Whenever errors appear, it’s surely that smell things happened. As the previous episode was written, The Pragmatic Programmer EP.4 — Tools, carefully read those error information. It’s trying to tell us something. Turn back to coding, we can use these techniques to produce fewer bugs.

Raise all possible cases

If you want to raise the exceptions, you should handle them for all cases that can happen. Otherwise, you should do this below because it won’t mislead what the real error is and you do have not to revise the exception handling section when you add more code.

Clash early

To avoid bugs that gonna happen, validating something before using is common sense. So, try to kick them out as fast as you know rather than let them flow until the end.

Assertions

You may have not known that assertion can be used in your functional codes, not only in testing codes. Yes, it can use to explicitly ensure that the value stored in a variable is in a state you expected. Let see.

Remember, no need to remove assertion from your production.

Always turn them on because they help us to ensure the value before using. As we know, a production always shares memories and other resources. This means that full memory allocation can easily happen rather than executing on your personal laptop. Even though you face a performance problem caused by assertions, don’t turn all of them off, but case-by-case.

Resources Balancing

Deallocate what you allocate at the same place

As you can see above block of codes, you may not think that are normal ones. But, let’s look closer. They share a file variable between 3 functions and the connection to the file has never been closed.

As a pragmatic programmer, you should aware of the resources. You have to deallocate what you have allocated. To be easy to deallocate it, we keep that file in the same place, not expose it to another function, like this:

In the case that you need to access the same resources in a different place, there are two suggestions available from the authors

  1. Try to deallocate resources in the opposite order in which you allocate them
  2. Try to allocate resources in the same order to avoid deadlock.

Fortunately, in object-oriented languages, garbage collectors are commonly available to automatically deallocate when an object goes out of scope e.g. Java.

In some languages, we can use a variable scope to handle resources, for example, C++. Meanwhile, in many languages, there are an except and a finally phases. Let’s see below:

Please carefully write logic using a finally clause, let’s imagine what will happen when open_file fail. Of course, a file will be closed where it didn’t open yet. So, it should be like this:

Speed Pace

Photo by Daniel Reche on Pixels

As an engineer, we normally trust what we see, not an oracle, or something that hard to predict. Hence, we just pace in small steps and get the feedback, for example, unit tests feedback (tell you what line you miss), security feedback, steak-holder feedback, feature feedback, and so on.

Please note that all examples shown above are samples to only emphasize understanding the concept. It may be simplified to comprehend, not correctly by the language syntax.

Thanks to The Pragmatic Programming book for above knowledge, if you are interested in reading this book, click here for more detail.

--

--

Natnicha R.
CodeX
Writer for

Software Engineer, Backend Designer, Algorithm Developer