I've recently read this blog post regarding what a constructor should do and I am also reading Eric Evans' book on Domain Driven Design.

Both the blog post and the book state that a constructor should have a bare minimum amount of logic in it, as to bring the object to a sane default state. But my question is, shouldn't immutable objects like the one below be an exception to this rule?

public class SomeReport
    public SomeReport(IReadOnlyList<Order> orders)
        this.Orders = orders;

        this.TotalWithoutTax = orders.Sum(o => o.TotalWithoutTax);
        this.TotalTax = orders.Sum(o => o.Tax);
        this.TotalWithTax = this.TotalWithoutTax + this.TotalTax;

        this.OutStandingOrders = orders.Where(o => o.RespectsSomeComplexBusinessRule()).ToList();
        this.TotalWithoutTax_OutStandingOrders = this.OutStandingOrders.Sum(o => o.TotalWithoutTax);
        this.TotalTax_OutStandingOrders = this.OutStandingOrders.Sum(o => o.Tax);
        this.TotalWithTax_OutStandingOrders = this.TotalWithoutTax_OutStandingOrders + this.TotalTax_OutStandingOrders;

    public IReadOnlyList<Order> Orders { get; }

    public decimal TotalWithoutTax { get; }

    public decimal TotalTax { get; }

    public decimal TotalWithTax { get; }

    public IReadOnlyList<Order> OutStandingOrders { get; }

    public decimal TotalWithoutTax_OutStandingOrders { get; }

    public decimal TotalTax_OutStandingOrders { get; }

    public decimal TotalWithTax_OutStandingOrders { get; }

Think of this object as being the container that will be sent to a PDF framework as input for a report for some business analyst (and ignore the fact that there may be some duplicated logic inside. The purpose of this class is to illustrate a complex initialization sequence for an immutable object).

As you can tell, the constructor could contain some complex logic like filtering, sorting and grouping in order to bring the input data into the shape required by the report, which in enterprise reports can mean some serious work.

In my opinion, this is very much in line with what OOP states about how data and behavior should work together inside the same construct to reach the desired goal.
If I were to split this class into a 2 different constructs, one that holds the data and one that assembles it (the factory) the way Eric Evans suggests in his book, I would essentially leave the realm of OOP and venture into the procedural/functional paradigms. Furthermore, I would lose (some of) the benefits of immutability, since from the moment the SomeReport POCO/POJO is initialized to the moment the factory is done initializing it, it is in an invalid state, thus violating the very purpose of a constructor - to have a valid instance of an object right after it has been called.

These being said, am I missing something else or when it comes to immutable objects it is a sane approach to do some heavy-lifting inside the constructor, since its initial state will also be its final state?

P.S: The heavy-lifting should be deterministic and if need be, computed properties can be made lazy.

  • see also: Is there ever a reason to do all an object's work in a constructor?
    – gnat
    Commented Jun 19, 2018 at 12:35
  • I'd actually make sure every one of those properties will be executed for every instance of this object. That's a lot of query and calculation going on, which can make the initialization expensive, depending on the number of orders you are processing. Commented Jun 19, 2018 at 12:38
  • 1
    Suggested links look like legit answers to my question. Thanks! This question can be marked as duplicated. Commented Jun 19, 2018 at 12:51
  • If you are using C# you don't really have to do a lot of complex logic in the constructor. You could always use named constructors, or static methods that do some logic and then dump the output into a separate constructor whose only purpose is to assign data to private fields.
    – Snoop
    Commented Jun 19, 2018 at 13:26
  • blog.thecodewhisperer.com/permalink/…
    – Snoop
    Commented Jun 19, 2018 at 13:28