DDD collection: include version control in model - domain-driven-design

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).

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).

Related

My segmented picker has normal Int values as tags, How is this passed to and from CoreData?

My SwiftUI segmented control picker uses plain Int ".tag(1)" etc values for its selection.
CoreData only has Int16, Int32 & Int64 options to choose from, and with any of those options it seems my picker selection and CoreData refuse to talk to each other.
How is this (??simple??) task achieved please?
I've tried every numeric based option within CoreData including Int16-64, doubles and floats, all of them break my code or simply just don't work.
Picker(selection: $addDogVM.gender, label: Text("Gender?")) {
Text("Boy ♂").tag(1)
Text("?").tag(2)
Text("Girl ♀").tag(3)
}
I expected any of the 3 CoreData Int options to work out of the box, and to be compatible with the (standard) Int used by the picker.
Each element of a segmented control is represented by an index of type Int, and this index therefore commences at 0.
So using your example of a segmented control with three segments (for example: Boy ♂, ?, Girl ♀), each segment is represented by three indexes 0, 1 & 2.
If the user selects the segmented control that represents Girl ♀, then...
segmentedControl.selectedSegmentIndex = 2
When storing a value using Core Data framework, that is to be represented as a segmented control index in the UI, I therefore always commence with 0.
Everything you read from this point onwards is programmer preference - that is and to be clear - there are a number of ways to achieve the same outcome and you should choose one that best suits you and your coding style. Note also that this can be confusing for a newcomer, so I would encourage patience. My only advice, keep things as simple as possible until you've tested and debugged and tested enough to understand the differences.
So to continue:
The Apple Documentation states that...
...on 64-bit platforms, Int is the same size as Int64.
So in the Core Data model editor (.xcdatamodeld file), I choose to apply an Integer 64 attribute type for any value that will be used as an Int in my code.
Also, somewhere, some time ago, I read that if there is no reason to use Integer 16 or Integer 32, then default to the use of Integer 64 in object model graph. (I assume Integer 16 or Integer 32 are kept for backward compatibility.) If I find that reference I'll link it here.
I could write about the use of scalar attribute types here and manually writing your managed object subclass/es by selecting in the attribute inspector Class Codegen = Manual/None, but honestly I have decided such added detail will only complicate matters.
So your "automatically generated by Core Data" managed object subclass/es (NSManagedObject) will use the optional NSNumber? wrapper...
You will therefore need to convert your persisted/saved data in your code.
I do this in two places... when I access the data and when I persist the data.
(Noting I assume your entity is of type Dog and an instance exists of dog i.e. let dog = Dog())
// access
tempGender = dog.gender as? Int
// save
dog.gender = tempGender as NSNumber?
In between, I use a "temp" var property of type Int to work with the segmented control.
// temporary property to use with segmented control
private var tempGender: Int?
UPDATE
I do the last part a little differently now...
Rather than convert the data in code, I made a simple extension to my managed object subclass to execute the conversion. So rather than accessing the Core Data attribute directly and manipulating the data in code, now I instead use this convenience var.
extension Dog {
var genderAsInt: Int {
get {
guard let gender = self.gender else { return 0 }
return Int(truncating: gender)
}
set {
self.gender = NSNumber(value: newValue)
}
}
}
Your picker code...
Picker(selection: $addDogVM.genderAsInt, label: Text("Gender?")) {
Text("Boy ♂").tag(0)
Text("?").tag(1)
Text("Girl ♀").tag(2)
}
Any questions, ask in the comments.

UML class diagram dependency or association

I'm not really sure about how to distinguish whether I should define a relationship as dependency or association for certain cases.
For example,
class AttendanceSheet {
Map<String> students;
boolean[] attend;
public void addStudent(Student s)
{
students.add(s.getName(),s.getStudentNumber());
}
public void checkAttendance(String name) { //... }
}
class Student {
private String name;
private int staffNumber;
//more information such as address, age, etc..
Student(String n, int sn)
{
name = n;
studentNumber = sn;
}
public String getName()
{
return name.clone();
}
public String getStudentNumber()
{
return studentNumber;
}
}
For this case, would Student and Association have association or dependency?
This is because I'm not sure whether the association must have the actual reference of the object or it suffice to just have certain information that can reach the object (since student id and number is far more enough to know find out which student object it is directing to).
In your case the <<uses>> is sufficient, because you don't have actual properties of type Student in AttendanceSheet.
As a side note: not using object references and instead just having the studentNumber is - to say the least - an odd design. But I don't know the context.
On the business level those objects are related, but there is no single preferred method of diagramming this relationship.
Please see Section 9.5.4 of UML specification for more details on the topic, especially Figure 9.12
To be specific those two notations are semantically equivalent (I'm ignoring irrelevant details):
In the first one to keep a traceability you can use an explicit Dependency pretty much the way you did.
One can also consider students as a Shared Aggregation, however it might be also considered an overkill. Not necessary, just showing a possibility for an answer completeness.
You may also consider Qulified associations to indicate a reference to the Student is based on their specific properties. This is pretty much closest to your need. Sorry, I don't know how to achieve such notation in my tool, but you can find more details in Figure 11.37 in Section 11.5 of the aforementioned specification.

DDD: How do structure or resolve more complex behaviour in a domain entity?

Assume the classic Order/OrderLine scenario.
public class Order {
...
public void AddOrderLine(OrderLine ol) {
this.OrderLines.Add(ol);
UpdateTaxes();
}
private void UpdateTaxes() {
//Traverse the order lines
//Collect the VAT amounts etc
//Update totals
var newTaxes = Orderlines.SelectMany(ol => ol.GetTaxes());
Taxes.Clear();
Taxes.Add(newTaxes);
}
}
Now, we figure that we need to handle taxes better, with different ways for customers in various countries etc, where some require VAT to be collected and others not.
In short, the tax rules will depend on the customer's location, items purchased etc. How would we do this? Should we put a lot of code into UpdateTaxes? Could we use tax calculator factory and reference it in UpdateTaxes?
private void UpdateTaxes() {
var taxRules = TaxRulesFactory.Get(this);
var taxes = taxRuleCalc.Apply(this);
Taxes.Clear();
Taxes.Add(taxes);
}
Considering your broader question regarding complex behaviour in ARs the preferred way to handle this would be to use double-dispatch. Bear in mind that complex behaviour certainly can be included in the AR if that behaviour is cohesive.
However, for functionality that varies to the degree of tax or even discount calculation, where one would implement various strategies, you could opt for the double dispatch:
public class Order
{
public void ApplyTax(ITaxService taxService)
{
_totalTax = taxService.Calculate(TotalCost());
}
public void ApplyDiscount(IDiscountService discountService)
{
_discount = discountService.GetDiscount(_orderLines.Count, TotalCost());
}
public Money TotalCost()
{
// return sum of Cost() of order lines
}
}
These services also should not be injected into the AR but rather passed into the relevant method.
May be you could extract UpdateTaxes into a separate class which would be responsible for tax calculation against a particular order. And itself would chose an appropriate strategy (a separate strategy class) depending on customer, order, etc. I feel that tax calculation is a separate responsibility here.
You might also have a think about whether the concept of Tax and the concept of Orders need to be located within the same bounded context. It perhaps seems logical or at least implicit that when you're in the process of creating an Order you will want to know Tax due, but does this necessarily apply in your domain?
I'm not saying it does or it doesn't, by the way -- I'm simply saying think about it for your particular domain. Very often when the model seems awkward to represent it's because it mixes concerns that don't belong together.

Setting a df threshold, beyond which, query terms should be ignored

I am using Solr to search and index products from a database. Products have two interesting fields : a name and a description. Product names are normally unique, but sometimes contain common words, which serve as a pre-description of the product. One example would be "UltraScrew - a motor powered screwdriver”. Names are generally much shorter than descriptions
The problem is that when one searches for a common term, documents that contain it in the name get an unwanted boost, over those that contain it only in the description. This is due to the fact that names are shorter, and even with the normalization added afterwards, it is quite visible.
I was wondering if it is possible to filter terms out of the name, not with a dictionary of stop words, but based on the relative document frequency of the term. That means, if a term appears in more than 10% of the available documents, it should be ignored when the name field is queried. The description field should be left untouched.
Is this generally possible?
maybe you could use your own similarity:
import org.apache.lucene.search.Similarity;
public class MySimilarity extends Similarity {
#Override
public float idf(int docFreq, int numDocs) {
float freq = ((float)docFreq)/((float)numDocs);
if (freq >=0.1) return 0;
return (float) (Math.log(numDocs / (double) (docFreq + 1)) + 1.0);
}
...
}
and use that one instead of the default one.
You can set the similarity for an indexSearcher at lucene level, see this other answer to a question.
I am not sure if I understood the question correctly, but you could run two separate queries. Pseudo code:
SearchResults nameSearchResults = search("name:X");
if (nameSearchResults.size() * 10 >= corpusSize) { // name-based search useless?
return search("description:X"); // use description-based search
} else {
return search("name:X description:X); // search both fields
}

Is it possible to do data type conversion on SQLBulkUpload from IDataReader?

I need to grab a large amount of data from one set of tables and SQLBulkInsert into another set...unfortunately the source tables are ALL varchar(max) and I would like the destination to be the correct type. Some tables are in the millions of rows...and (for far too pointless policital reasons to go into) we can't use SSIS.
On top of that, some "bool" values are stored as "Y/N", some "0/1", some "T/F" some "true/false" and finally some "on/off".
Is there a way to overload IDataReader to perform type conversion? Would need to be on a per-column basis I guess?
An alternative (and might be the best solution) is to put a mapper in place (perhaps AutoMapper or custom) and use EF to load from one object and map into the other? This would provoide a lot of control but also require a lot of boilerplate code for every property :(
In the end I wrote a base wrapper class to hold the SQLDataReader, and implementing the IDataReader methods just to call the SQLDataReader method.
Then inherit from the base class and override GetValue on a per-case basis, looking for the column names that need translating:
public override object GetValue(int i)
{
var landingColumn = GetName(i);
string landingValue = base.GetValue(i).ToString();
object stagingValue = null;
switch (landingColumn)
{
case "D4DTE": stagingValue = landingValue.FromStringDate(); break;
case "D4BRAR": stagingValue = landingValue.ToDecimal(); break;
default:
stagingValue = landingValue;
break;
}
return stagingValue;
}
Works well, is extensible, and very fast thanks to SQLBulkUpload. OK, so there's a small maintenance overhead, but since the source columns will very rarely change, this doesn't really affect anything.

Resources