Skip to main content

Clean Code – Boundaries, Error Handling and Objects

In the last 3 months I tried to talk about different subjects presented in Clean Code. Even if this is the 4th article about this topic, I have the feeling that there are so many things that we should talk about when we are talking about a clean and good written code.
We could say that ‘Clean Code’ book, written by Robert C. set the standards in our industry from this perspective. It is the developers Bible and many times it is a used as the ‘law’ of the code. I don’t want to go deeper into this subject, but I promise that one time I will talk in details why/why not we should use this book as THE Bible.

Today topics

In this article I will try to talk about Objects and Data Structure, Error Handling and Boundaries I expect to go from the code format, to how the code should look like and how we should implement different features.

Objects and Data Structure
I think that all of us remember the University courses, when teachers try to explain us that we should only expose from a class, only the information that is needed by others. But, because current programing language give us so easily the possibility to expose a data outside a class there are many times when we end up with a lot of private data exposed to the system.
One of my colleges called gets and setter the tool of devil. It is funny, but sometimes is true.
It is not so important if we are using a getter/setter of a method. The most important thing is to expose the data in an abstract way, that don’t expose , that don’t expose implementation details. For example if we need to expose information related to the weight of a person,  we can use a getter or a simple method. Botch solutions are good as long as we don’t give any kind of implementation details.
public class Person
{
    public double WeightInKg
    {
        ...
    }
    // OR
    public double GetWeightInKg()
    {
        ...
    }
}
Outside this class, you don’t know how the data look like and what the format of it is. If we would add getters and setters everywhere, what would be the value of encapsulation … NONE.
Be aware that there is a big difference between data structures and objects. You should keep this in mind when to start to write code. The best things that you can do is to keep a clear like between this two.
Data Structure exposes only data, but without any kind of functionality, in contrast with objects, that expose only functionality. Of course we need to keep in mind that the balance between this two I hard to keep. You will need a data structure that expose functionality. You only need to keep in mind what data you want expose and where the functionality implementation should be added.
When you implement a functionality you should talk only with friends and never with strangers (The Law of Demeter). This mean a function should only access/call:

  • Methods from the class where is implemented
  • Methods from objects created in the methods itself
  • Methods from objects that are send as arguments
  • Methods from objects help as instances in the class where method is implemented


Hybrids
Hybrid structures are objects that contains also data structure. The problem with them is that is pretty hard to add new functionality or data to it. It’s create a confusion because you don’t know what you should add there. It can indicate that is it not clear the purpose of that entity and if data protection was needed.

Data Structure Object
There are used a lot when we need to store data somewhere (DB) or send data over the wire. They are called DTO and usually don’t have any kind of functionality. The purpose of them is good, but we should keep in mind that we should use them only for the purpose that they were created. Otherwise a change in the data structure would trigger a lot of changes in our code.
On top of DTO we have Active Records, that are similar with DTOs, but ha methods used for navigation like Find, Save, Delete, Send and so on. This functionality is usually offered by DB for example. The problem with them is that developers usually use them like objects and other functionality is added to them. Because of this we end up with an Active Record that has business logic inside.
What we should do? Create Active Records that store only the data structure and use separate objects to store the business rules.

Error Handling
Why we need to talk about error handling? Because even if the main purpose of a code is not error handling, is the functionality that is implemented, we end up with code where only error handling can be seen and it is almost impossible for us to find the details about the real functionality that is exposed there.
To avoid this situations, there are small things that can be done at code level. First of all, avoid using error codes. This adds a lot of code to your methods and hide information the exception itself. Also, the caller needs to check every time the return code and implement a custom handler for different error codes.
Exception can be used with success with try/catch blocs that can be seen as a ‘transaction’ block, where you expect exception and you are ready to handle them. Also, it is a clear separation between the functionality and the exception handling.
try
{
    // Functionality
} catch (FantaException nullEx)
{
    ...
} catch (CokeException nullEx)
{
    ...
}
It is important to remember that the function n that throws an expectation, should provide enough content about the source of the error. We should try to define specific exceptions based on caller’s needs. Why? Because the main purpose of them is to help the caller to find out the root of the issues.
Nulls
You should never do two things. Pass a NULL to another function, because the function will need to check if is null or not and to manage this situation. You basically pass the problem to another function, but without resolving it.
And you should NEVER return a NULL. The caller will need to check the result if is null or not and add a specific handler. You should better return an exception that can be cached and managed by the caller.

Boundaries
We are surrounded by boundaries. When we are using 3rd parties libraries, code implemented by other team, core API and so on. In all this situation, we have a boundary that is set and a set of function that we can use to cross over it.

It is important to know how to keep this boundaries clean and useful. The first thing that we should do when we need to use an external resource is to reserve time to learn and explore it. We need to discover the boundary, how we need to manage and use the functionality expose by it.
The easiest way to learn is by writing test that validate different scenarios. In this way we can be sure 100% that different flows will work and we know how to handle them. Also, we will be able to validate that the 3rd party offers what we really need.
When we have external 3rd parties that expose boundaries it is mandatory to define an adapter that would isolate us from the 3rd party library. We will have cases when we will need to fake the behavior or when 3rd party API will change. In this case we don’t want to create a domino effect in all our code.
The adapter should not expose 1:1 the functionality expose by 3rd party. It should expose the functionality what we need, not the one that is offered. All details implemented should be putted in the adapter itself.

Conclusion
There are so many other things to say about topics that were touched in this article. There 3 things that I would like you to remember from this article:

  • The different between an object and a data structure 
  • Never return a NULL, or forward a NULL to another method
  • An adapter for a boundary should expose the functionality that you need, not the one exposed by the 3rd party

And YES, all of us should read ‘Clean Code’.

Comments

Popular posts from this blog

How to check in AngularJS if a service was register or not

There are cases when you need to check in a service or a controller was register in AngularJS.
For example a valid use case is when you have the same implementation running on multiple application. In this case, you may want to intercept the HTTP provider and add a custom step there. This step don’t needs to run on all the application, only in the one where the service exist and register.
A solution for this case would be to have a flag in the configuration that specify this. In the core you would have an IF that would check the value of this flag.
Another solution is to check if a specific service was register in AngularJS or not. If the service was register that you would execute your own logic.
To check if a service was register or not in AngularJS container you need to call the ‘has’ method of ‘inhector’. It will return TRUE if the service was register.
if ($injector.has('httpInterceptorService')) { $httpProvider.interceptors.push('httpInterceptorService&#…

ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded

Today blog post will be started with the following error when running DB tests on the CI machine:
threw exception: System.InvalidOperationException: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information. at System.Data.Entity.Infrastructure.DependencyResolution.ProviderServicesFactory.GetInstance(String providerTypeName, String providerInvariantName) This error happened only on the Continuous Integration machine. On the devs machines, everything has fine. The classic problem – on my machine it’s working. The CI has the following configuration:

TeamCity.NET 4.51EF 6.0.2VS2013
It seems that there …

Run native .NET application in Docker (.NET Framework 4.6.2)

Scope
The main scope of this post is to see how we can run a legacy application written in .NET Framework in Docker.

Context
First of all, let’s define what is a legacy application in our context. By a legacy application we understand an application that runs .NET Framework 3.5 or higher in a production environment where we don’t have any more the people or documentation that would help us to understand what is happening behind the scene.
In this scenarios, you might want to migrate the current solution from a standard environment to Docker. There are many advantages for such a migration, like:

Continuous DeploymentTestingIsolationSecurity at container levelVersioning ControlEnvironment Standardization
Until now, we didn’t had the possibility to run a .NET application in Docker. With .NET Core, there was support for .NET Core in Docker, but migration from a full .NET framework to .NET Core can be costly and even impossible. Not only because of lack of features, but also because once you…