The Importance of Proper Programming

What happens when we have methods or functions that perform unexpected actions? Most likely, our code will crash. In this post, we’ll see how to avoid unexpected situations.

 

 

 

1 - Quality Code Exists

 

There’s rarely anything certain in this field, but I can speak from experience.

 

Personally, I have a way of programming that not everyone appreciates, since one of my premises is that my applications are never in an invalid state.

What do I mean by an invalid state? Very simply, as long as the state of my program is correct, the correct functioning of the code is guaranteed. That way, if the program crashes, it is very likely that there’s a bug or the assumptions made are false.

 

When you apply the right tools and techniques to code, its quality increases. When I say code is high quality, I usually look at three aspects:

 

1 - It does the job it’s supposed to do.

2 - It’s easy to read and understand.

3 - Expected situations do not produce unexpected situations.

 

With these three points, you can say it’s quality software because it works as expected, does it well, and doesn’t break. Additionally, depending on the situation, I might add a fourth point: it does so efficiently. But not all applications require this fourth point.

 

You might think these points are just common sense, but they’re not that simple. The second is achieved mainly through years of experience and code reviews by other developers.

 

But the third not only depends on years of experience and peer reviews but also on the language we use and the tools that language provides to make our lives easier.

 

 

2 - Anticipating the Unexpected: The Key to Predictable Code

 

Unfortunately, this post mainly comes from the need to vent about situations I’ve recently experienced. But at the same time, it’s an opportunity to explain how to do things right.

 

Throughout this post, we’re mainly going to focus on the third point I previously mentioned: ensuring that expected situations do not produce unexpected results. For this, what we have to do is turn unexpected scenarios into expected ones.

It sounds very simple, but it isn’t. Each day it gets a little easier, as we now have tools like static code analysis for practically every language. The use of types also helps (yes, I’m a fan of using types), and of course, the tools of each language, whether it’s the C# compiler or EsLint (I know it’s static code analysis) in JS; in Ruby, we can use... nothing, in Ruby you can add types but not much else :D.

 

The idea is simple: analyze the code to avoid unexpected situations.

In this post, all the code is C#, and in my opinion, based on my experience, it’s one of the best languages for maintaining constant and predictable program states.

 

Note: The term in English is "software invariance," but I don’t know how to translate it, and I find it easier to just say what it means.

 

Later we’ll see how the following code, if everything is well set up and you know what you’re doing, isn’t possible in C#. Unfortunately, there are people who don’t pay much attention or don’t have time to stop and think, and it can contain errors. If we don’t have something telling us that we are doing something wrong, we might end up in an unexpected situation:

 

Let’s suppose we receive, from an API, a database, or any source, a vehicle object, which among other properties contains speed in kilometers.

 

And since our users are in the United States, we simply convert it to miles.

public class Vehicle
{
    public decimal SpeedInKm { get; set; }
}

decimal CalculateMiles(Vehicle vehicle)
{
    return vehicle.SpeedInKm * 0.62137119223733m;
}

At first glance, this code looks fine: we pass the vehicle, get the miles, and do the calculation.

 

But wait, my friend, what if the vehicle or speed is null? Or undefined, like in JS?

At this point, our code will crash and throw an exception.

 

 

3 - Use Nullable Code

 

The first action we can take is to use nullable code. We should enable nullable in the csproj, and in our type definition, we can specify that the speed property can be null using the ? character.

public class Vehicle
{
    public decimal? SpeedInKm { get; set; }
}

//In the csproj
<PropertyGroup>
    <Nullable>enable</Nullable>
</PropertyGroup>

This way, the compiler will give us an error and we have to change the method result.

decimal? CalculateMiles(Vehicle vehicle)
{
    return vehicle.SpeedInKm * 0.62137119223733m;
}

 

IMPORTANT in C#: in recent versions, we don’t have to change the method body; the compiler automatically adds an if statement at compile time. You can see this in the generated code after compilation:

nullable IL rider

But in other languages, you’ll have to put the IF manually. And of course, check every property that can be null at every point where it needs to be used.

 

As an additional note, in C# I recommend enabling nullable within csproj on all projects you use. Nulls are a serious problem, especially in legacy applications.

 

 

4 - Warnings Are Errors

 

Personally, I’ve spent years advocating that code warnings are errors. This means all those yellow alerts we see when building shouldn’t be ignored; they should be fixed.

 

Why? Because every warning we ignore is a place where our application will crash, not might, but will. The question isn’t if it will fail, but when.

 

Let’s use the code from the beginning again:

public class Vehicle
{
    public decimal SpeedInKm { get; set; }
}

decimal CalculateMiles(Vehicle vehicle)
{
    return vehicle.SpeedInKm * 0.62137119223733m;
}

Now, in our use case, let’s pass a null vehicle object:

CalculateMiles(null);

What do you think happens here?

 

We have two situations:

1 - If nullable is disabled, nothing happens.

2 - If nullable is enabled, we’ll see a warning: "Possible null reference."

 

In both cases, the code compiles and we can put it into production. Of course, if a null value enters our CalculateMiles method, the code will crash and throw an exception.

 

In C#, we can enable the TreatWarningsAsErrors property in the csproj, which will turn that warning into an error and prevent the program from compiling.

<PropertyGroup>
    <Nullable>enable</Nullable>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

So what we need to do is fix the problem so it doesn’t produce an error.

 

In our case, that means specifying both the input and output parameters as nullable and checking if the vehicle is null before accessing the speed.

decimal? CalculateMiles(Vehicle? vehicle)
{
    return vehicle?.SpeedInKm * 0.62137119223733m;
}

And now it compiles and the code is protected from breaking.

 

One additional note with TreatWarningsAsErrors: if you add it to code that’s been running for years, you’ll likely have thousands of warnings. So, I recommend enabling it on new projects.

 

 

5 - Fix Root Problems

 

Specifying that the vehicle can be null and checking for null at every step may not be the best approach.

 

Let me explain: what we’re doing is, if the vehicle is null, speed is also null. But if the vehicle is null, why check speed or any other property on that object? We already know it’s null; it doesn’t make sense.

 

So, in this specific case, what we should do is an early exit, which means not processing anything after validating that it’s null. In this simple example, it’s just an if. You’ll notice that if you use an if to exit the code, you can make the method not accept nulls:

Vehicle? currentVehicle = externalApi.GetVehicle();

if (currentVehicle is null)
{
    return;
}

CalculateMiles(currentVehicle);

decimal CalculateMiles(Vehicle vehicle)
{
    return vehicle.SpeedInKm * 0.62137119223733m;
}

This means we’re going to guarantee a valid system state, which is extremely beneficial in the long run.

 

 

 

Conclusion

 

The example we’ve covered is a simple one, but I hope it has helped you see the differences between doing things right or not.

 

The correct use of types not only improves your code in production, but it also helps anyone making changes understand what might happen.

For example, if you have a method that receives a list and returns a filtered one, generally you expect the list to be returned. But it can happen that if there are no elements, the list is returned as null.

Why would someone do that? I have no idea, but that’s exactly the kind of case that made me write this post. By the way, null is not the same as an empty string or an empty list, among other things.

 

Finally, if you combine what you’ve learned here with what we covered about immutable code, you’ll achieve consistent and high-quality code.

 

Every improvement you make to your code saves time in the future, not just for you, but for your team. And every bug that never reaches production means a happier client, which, after all, is who pays the bills.

 

This post was translated from Spanish. You can see the original one here.
If there is any problem you can add a comment bellow or contact me in the website's contact form

Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café