Hi! And welcome to this lesson. Today, we’re going to look at good programming practices.

Why adopt good programming practices?

Coding is not just about writing lines of codes, one after the other. It’s complex and challenging, and requires a certain degree of skill. 

I’m going to introduce a few important good practices that you should always keep in mind while coding.

Do not optimize first

First, do not optimize first!

As we’ll see in the coming weeks, coding is often a case of finding the best compromise between correctness of the code and speed. The problem is that achieving a good speed boils down to exploiting adapted data structures, using elaborate algorithms, and sometimes even using low-level tricks to accelerate computations. In many cases, these optimizations have an impact on the readability of the code, which can make it more difficult to see what it does.

You should always have a correct program before optimizing, and there’s no need to consider speed at this point.

Optimizations can be implemented later. It’s always much simpler to debug a code that was built to be correct rather than a code that was optimized in terms of speed.

Structure the code

It’s no secret that coding is difficult. And why’s this? Because programming languages are not meant to be easily understood by humans, but to be easily processed by machines.

Writing code means that you can explicitly describe the details of a given method in a way that is unambiguous.

In other words, writing code involves describing a method using elementary notions available in a programming language.

Most of the time, a programmer doesn’t think about the low-level programming language itself, but uses abstract language layers.

Let’s take the example of finding the shortest path in a graph. There’s no such thing as a function find_the_shortest_path(maze) in Python. We’re going to code this function so that we can use it to perform more complex tasks.

Coding is all about stacking up more and more abstract layers, until your program can be written with the help of just a few functions.

In this course, we will use graph theory to play a game in a maze. For this, we’re start off by finding paths, then finding the shortest path, then multiple shortest paths, then we’ll take the opponent into account.

This process is called structuring the code. And a code should always be structured.

As a rule of thumb, you should always try to code functions that are no more than 15 lines long. If it contains more than that, then you should probably try to split your function into multiple subfunctions.

Factorize the code

A programmer should never — EVER — use the copy/paste shortcuts when developing a code.
However, if you SHOULD ever wish to do this, then you should create a subfunction containing the lines you want to duplicate.

This process is very important, because one day you might want to modify your code, update the code to take into account new inputs, or optimize part of the code. It’s much simpler when parts of the code to be updated are at one location.

A common source of errors is when duplicated lines are modified but you forget to change other occurrences in your code.

No mysterious constants

Anything that appears to be arbitrary in a code should be avoided.

For example, you might want to use the number « infinity » in your code, but such a thing doesn’t exist in computer memory.

One trick would be to use a large number instead, say 100,000, which should be defined once at the beginning of your code using an explicit name, like infinity_value. When you next look at your code, perhaps years from now, it will be much easier to understand what infinity_value is than 100,000.

Remark (outside of transcripts): This is an example for illustrating the message. In practice, Python has a pretty good way of handling « standard » numbers (infinity, pi, etc.), that you should favor rather than setting constants. You may want to have a quick Google search about this, or just check float("inf").

Explicit inputs/outputs and comments

Finally, you should always write your code thinking that it will be read by someone else.

This is obviously the case if you’re working in a team, but even if you’re not, adding comments is a good way to be sure that what you’re doing is correct.

A good way of using comments is to write them first, and then add code sparingly between comments.

If you don’t know what comments to write, begin with an explicit description of a function before you write the corresponding code.

This should contain a short description of how it works, details about the parameters and outputs, and remarks about correctness conditions.

Coding is not and should never be a question of the number of lines of codes written per minute.

If it takes one hour to write one line, then so be it. Maybe that single line will be used by hundreds or thousands of programmers, so it can be worth every moment.

Concluding words

If you follow all these principles, then you have all the keys to becoming a great programmer.

Thanks for watching this lesson. I how you will now adopt good programming practices. See you next time!

Unit testing

Beyond coding conventions, it is important to be confident that the code you write works. There are multiple approaches to do this. A prevalent one is called unit testing.

In brief, a unit test is a small code that will check that the function you wrote produces the expected outputs for some given inputs.

As an example, let’s assume you want to program a function that adds 1 to a number if it is even, and 3 if it is odd:

def add_one_or_three (a):
    if a % 2 == 0:
        return a + 1
    else:
        return a + 3

A good test for this function should test all possible execution scenarios to make sure that it works correctly in all cases:

def test_add_one_or_three ():
    assert add_one_or_three(1) == 4
    assert add_one_or_three(0) == 1

This is obviously a simplistic example. In real scenarios, you may want to test as many cases as you can identify. Also, you may want to test all error scenarios, making sure that inappropriate use of a function leads to the correct exception (e.g., the square root of a negative number).

In the first lab session, you will learn to use a dedicated Python library for unit testing. As for respecting the coding conventions, we ask you to test your functions to make sure that they work, before using them for developing new functions.



To go further

  • The programming rules in this article come from the work of Knuth. You may find his books interesting on many aspects.

Quiz

Which of the following are good programming practices?
Indicate which of the following numbers of lines are acceptable for a function: