c# – Is it bad practice to do too much inside a builder? Why?

Question:

Is performing heavy processing, such as queries to a database or consuming an API, inside class constructors considered bad practice? Why?

public class Classe
{
    private String dados;

    public Classe()
    {
        // ...
        dados = Database.GetDados();
        // ...
    }
}

Would it be better to do it this way or similar, taking the processing out of the constructor?

public class Classe
{
    private String dados;

    public Classe()
    {
        // ...
    }

    public void Inicializar()
    {
        dados = Database.GetDados();
    }
}

And when "building":

public void Call()
{
    Classe x = new Classe();
    x.Inicializar();
}

I've heard from some higher education professors saying it's a bad practice, but I don't see why. Shouldn't the object be constructed and its dependencies at the same time?

Answer:

"Is it bad to do a lot inside builders?"

If too much is not fast, define fast as a requirement of your application and the response time that is satisfactory for the object in question.

"Doing heavy processing, like DB queries, inside builders is considered a bad practice? Why?"

Yes. Because instantiating an object is commonplace and should be fast, we generally avoid operations that we know are cumbersome and most of the time are being done in the constructor because the programmer tries to ensure that things will be there later, and usually he doesn't need to of them in the constructor. In your example, you just load the property, you don't use it in the builder flow, so you could leave that action for when the property is actually used.

If you really need to perform this operation in the object during construction, you should consider the scenarios where this object will be used, because, as you do something big in the constructor, certain operations with objects that are commonplace have a direct impact on the application , here are some examples.

1 – Listing of objects for grids/tables: it is common to create screens where the system lists (including paging) objects for a user to operate on. As you necessarily have to instantiate the object to show the data, even if it's just the name and the ID, you'll have a ridiculously slow grid, consuming memory, database and application needlessly.

Alternatives that can improve your life: Lazy Load.

2 – Strong coupling: Generally an object that has a slow constructor is a complex object, which may need to access several data sources and instantiate several other objects, so its implementation must be careful with coupling the concrete classes. This can also make your layers (if this is your architecture) confusing.

Alternatives That Can Improve Your Life: Dependency Injection

3 – Calls to build other complex objects that have constructors as complex as the one you are building. Oo (this sentence looks cool): You can attach an object that needs to be constructed by calling a second complex constructor, but that will only be used in certain situations (sounds like a lazy load case :)) and sometimes you may not even need it .

Alternatives that can improve your life: proxy object.

As a matter of fact, in some scenarios you rarely escape the fact that you have to build heavy objects, but most frameworks solve this for you and already have these design patterns in place.

If you use Entity Framework, for example, the lazy load is already there for you almost natively. You just need to ask to use it. Many modern object-oriented applications use ORMs and this makes it easier to implement these techniques because this happens a lot with objects that need to be stored in databases and programmers come to know design patterns as an ORM feature, not a generic solution that he can implement it himself.

But, this is a lack of knowledge and not a restriction of the pattern, you could use the pattern to slow down loading a texture of a file that comes from disk, not necessarily from the bank.

It's important to note that I responded using the .NET context, but much of what I've written here is a general solution on most OOP platforms, Java is a great example.

Bringing some of this to your code example:

public class Classe
{
    private String dados;

    public Classe()
    {
        // ...
        dados = Database.GetDados();
        // ...
    }
}

Your class needs to know the concrete implementation of the Database class (tight coupling, even if it's just the interface.

Your class necessarily goes to the database to load the data attribute, even if you don't use it. Imagine another attribute name that you use in the grid but is returned in the constructor, something like:

public class Classe
{
    private String dados;
    private String nome;    

    public Classe()
    {
        // ...
        dados = Database.GetDados();
        nome = Database.GetNome();
        // ...
    }
}

In this case, in addition to coupling, you would be going to the database twice, even if you only need to show the name in the grid/table/screen. Classic waste of resources and performance. A proxy Object/lazy load would leave this load for later, making the object to be instantiated much faster and you only give a pass to the database for what you really need.

"Would it be better to do it this way or something like it, taking the processing out of the constructor?"

No. Because many times the implementer of a class is not its user, so you don't guarantee that the users of your class will call this method, which ends up introducing a point of failure in the application. Another important and conceptual factor is that you are just delaying the builder's actions for a secondary method, but there is no golden rule, it depends on what you are doing.

If possible, avoid distortions of the already consolidated design patterns, they are there because people much better than us have already faced this.

Scroll to Top