1

In my DDD attempt I've defined the following ubiquitous language:

A product can have multiple drawings. A drawing consists of a drawing number, a revision number* and multiple attachments**. A drawing can be revised by a new drawing with a different revision number.

Invariants:

  • for every drawing number a product has, there can only be one current revision.
  • there can be no drawings with the same drawing number and revision

*sometimes initially empty
**the attachments are the actual product drawings, can be .jpg, .pdf, .stp, etc.
Is there a mismatch in the language? These attachments can also be called the actual drawings where the above properties are merely metadata to programmatically distinguish them.

Some context, the application should help the business with the development of products. The drawings are concepts that after discussion and revisions will form a sample that must be approved by the customer. For this context, I've chosen an event-sourcing architecture because of the business value to evaluate the incremental development of products.


The problem I'm having is whether to put these past revisions in the model. This could be done by adding a boolean property to the drawings that indicate if they are the currently used drawing. This however goes against my gut-feeling to model drawings as immutable value objects (now the drawing has a mutable property). In my mind I've supported this gut-feeling with the argument that once a drawing is changed this results in a new drawing with a different revision number.

Another gut-feeling I have though, is that I should put the past revisions in the model as they have business value. Is it a good solution to let a product have a list of current drawings and past drawings?

How should I think about when a user wants to correct a drawing? For example, when someone didn't attach all correct files to the drawing and you later want to correct this by adding more files, or removing some?


Code example

To give a brief example with some code, this is one of the things I came up with, the drawing as an value-object that uses the drawing number and revision in the equals method:

    public class Product {

        private Set<Drawing> currentDrawings;
        private Set<Drawing> oldDrawings;

    }

    public class Drawing {

        private String drawingNumber;
        private String revision;
        private Set<URL> files;

        @Override 
        public boolean equals(Object o) {
            if (o == this) return true;
            if (!(o instanceof Drawing)) return false;
            Drawing other = (Drawing ) o;
            if (this.drawingNumber != other.drawingNumber) return false;
            if (this.revision != other.revision) return false;
            return true;
        }

        //getters and constructor omitted for brevity
    }

Not enough reputation to answer Luiz E's comment, so I'll put it here instead: in some cases a product consists of different parts, materials, and so forth. Sometimes there's a clear parent drawing that referenced other subdrawings, other times there are just a bunch of drawings of parts that will be assembled later.

I tend to adhere to the "KISS" principle, instead of modeling all these different relations between the drawings that will only confuse the users (they are not the creators of the drawings).

Taemera
  • 25
  • 1
  • 4
  • 1
    I had the feeling that the Drawing, from a client perspective, is unique: a product has one drawing. of course, you can have multiple so that you have a history, a version control so to say, but the latest drawing will be valid. is that correct? did I miss something? – Luiz E. Jul 19 '18 at 02:38
  • In some cases a product consists of different parts, materials, and so forth. Sometimes there's a clear parent drawing that referenced other subdrawings, other times there are just a bunch of drawings of parts that will be assembled later. I tend to adhere to the "KISS" principle, instead of modeling all these different relations between the drawings that will only confuse the users (they are not the creators of the drawings). – Taemera Jul 19 '18 at 08:13

1 Answers1

0

For future references, when designing an aggregate according to DDD principles, one should keep the aggregate clean and not pollute the model with earlier versions of (parts of) the aggregate. Keep in mind that you want the model to represent the current state of the aggregate.

If earlier states of (parts of) the aggregate have some sort of business value, you should consider event-sourcing or other patterns that allow an audit log or version control.

For this specific question, the Product aggregate and the Drawing value-object might look like this:

public class Product {

    private Map<String, Drawing> drawings;

}

public class Drawing {

    private String drawingNumber;
    private String revision;
    private Set<URL> files;

    @Override 
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof Drawing)) return false;
        Drawing other = (Drawing ) o;
        if (this.drawingNumber != other.drawingNumber) return false;
        if (this.revision != other.revision) return false;
        return true;
    }

    //getters and constructor omitted for brevity
}

The reason I would prefer Map over Set here is that you want to have only one revision per drawing number and every Drawing must have an unique drawing number. This is easy to achieve if you use the drawing number as the Key value in a Map and simply put the revised Drawing on the drawing number Key, as this will replace the old Value object.

As a drawing should be considered equal by comparing their drawing number and revision, it would be harder (not impossible) to check if there are no duplicate drawing numbers. You can solve this by only comparing Drawings to their drawing number, but this would undermine the definition of a revision (an correction to the Drawing, which makes it a different Drawing).

Taemera
  • 25
  • 1
  • 4
  • 1
    then according to your comment, I also think that a Drawing should reference a parent Drawing...what do you think? – Luiz E. Jul 19 '18 at 11:20
  • 1
    I think that would be overmodeling it a bit, because I haven't come across situations where this extra distinction gives extra business value. The collection of drawings will later be an attachment to an email and the drawing numbers are mentioned in enquiries and quotations. Maybe they want to display only one drawing number when there's a clear parent drawing (to save space if there are a lot of drawings), that will be a next discussion point when I'm meeting with the domain expert. – Taemera Jul 19 '18 at 12:00
  • got it. on another topic: change to a map would be an overmodeling I think since you'll duplicate the revision num. (both on the key and on the drawing itself). I don't see why you would need an map in this case, the Set would suit you fine – Luiz E. Jul 19 '18 at 12:16
  • Do you mean I'm duplicating data because I'm reusing an object's field as a key in a Map? That's common usage afaik. A Set is a collection interface that cannot contain duplicates. Drawings with the same drawing number and a different revision are not equal but still should not be allowed, so a Set does not fulfill that requirement. Also, when revising a Drawing I want to check if there already is a drawing number with given revision, but a Set does not allow to directly get a Drawing. I have to code away this to get a Drawing by its drawing number, while a Map already offers this. – Taemera Jul 19 '18 at 13:12
  • I see...well, then I think you are on the right path with `Map` – Luiz E. Jul 19 '18 at 13:15