4

I believe the scenario is common mostly in business workflows - for example: loan management

the process starts with a loan application, then there's the loan offer, the 'live' loan, and maybe also finished loans.

  • all these objects are related, and share many fields
  • all these objects have also many fields that are unique for each entity
  • the variety of objects maybe large, and the transformation between the may not be linear (for example: a single loan application may end up as several loans of different types)

How would you model this?

some options:

  • an entity for each type, each containing the relevant fields (possibly grouping related fields as sub entities) - leads to duplication of data.

  • an entity for each object, but instead of duplicating data, each object has a reference to it's predecessor (the loan doesn't contain the loaner details, but a reference to the loan application) - this causes coupling between the object structure, and the way it was created. if we change the loan application, it shouldn't effect the structure of the loan entity.

  • one large entity, with fields for the whole life cycle - this can create 'mega objects' with many fields. it also doesn't work well when there's a one to many or many to many relation between the phases.

4

One of the most eye-opening events for me was learning about Color-Based Modeling. It totally transformed my approach to designing systems.

The key idea is that there are four archetypes in object-oriented design:

  1. Moment-Interval represents an event, or a span of time. For instance applying for a loan is a Moment the entire process from application to closure of the loan would be an Interval
  2. Role represents participants in a Moment-Interval. Sticking with the loan, an Applicant would be one role, the loan officer would be another, underwriters would be a third.
  3. Descriptor represents a label or a "class" of objects. For example, you might have a descriptor for Home Loans versus Auto Loans but the loans themselves are fundamentally the same. The Descriptor can also act as a factory. I usually use descriptors where people normally use Enums.
  4. Person/Place/Thing represents a physical, tangible object. Michael Brown is a person, Global Corp. Headquarters is a Place, Dell Precision Laptop with serial number 12345 is a thing. (Note my specific Dell Precision Laptop would possibly have a descriptor attached to it in Dell's E-commerce system).

Those are the 4 basic elements of an O-O model. And here is how it relates to your question.

The very first archetype is the Moment-Interval. If you recall one of the guidelines for basic object-oriented programming "Objects are Nouns, Methods are Verbs" you might be tempted to represent the loan application as a method "ApplyForLoan" on the Applicant object and store all the information about the application on a single Loan object. Then you might be tempted to have a "LoanStatus" enumeration on the Loan that basically lists all the phases the loan goes through as it's being processed.

The better way is to have an Application moment object. And an Applicant role object. Roles are attached to Person/Place/Thing and participate in moments (in practice, I usually give the responsibility for creating a Moment object to a Role that I identify as the "actor". In the case of the loan application the Applicant is the "actor".

Within the book, Coad talks about the concept of Predecessors and Successors. I.e. before a RiskAssessment can be performed, there must be an Application. The Moments form a chain of events that are pertinent to the system being created. For instance the loan approval system would not care about payments on the loan so they wouldn't be mapped as part of the system. Although there might be another system that does deal with these details.

The beautiful part of this approach is that the system becomes very flexible and extensible because rather than sticking new fields and methods on a bloated "LoanCustomer" object (or worse deriving from loan customer to represent different roles the customer might play in the system), we create new roles as the needs of the system grows.

I'd HIGHLY recommend picking the book up and going through it. It's a very powerful technique despite the fact that UML is no longer in favor, the concepts are timeless.

4

If I were you, I'd keep my data immutable. It's much safer and simpler to reason about; when you manage money, this feels especially important.

Each phase of the loan application process would be represented by its own class, describing that phase in the most adequate way, and a link to the previous phase.

Where it is cheap, I'd copy data from the previous phase: for instance, numbers. Strings are probably also easy to 'copy' if you're using a language where strings re immutable and interned, and you just copy a reference.

If a large amount of data has to be shared with a previous phase (a data table, a document scan, etc), these data probably form its own object, referred to from each phase that uses it.

Of course, I'd make every sub-object of these objects immutable, too. If a list of offer changes, it's another object that represents the change and holds both old and new lists, both immutable.

Upsides:

  • Your data mapping is straightforward so talking to business people becomes easier.
  • You have a complete picture of how your data evolved, great for bug hunting or testing, troubleshooting, reporting, and auditing.
  • You'll never be able to lose data through a bug in data modification logic. (If you do multi-threading, whole classes of data race and concurrent modification bugs just go away, too.)
  • Each phase has the best, no-compromise representation and no extra 'unused' fields.
  • Your type system helps you to always use a correct phase-of-workflow object, detecting many possible bugs at compile time.

Downsides:

  • You have many interdependent classes, sometimes deceptively similar.
  • Changing business logic may take a bit more changes in code.

Here's the key part of an article describing this approach. It uses Scala, but the it explains the rationale in plain English. Feel free to take a look at previous parts that show the downsides of a mutable objects approach.

  • "Where it is cheap, I'd copy data from the previous phase": my main concern is not data storage or computation efficiency, but the copying code which tends to be hard to maintain. From other aspects it appears a good solution. – Ophir Yoktan Nov 12 '13 at 6:22
  • Which kind of code do you suspect will be hard to maintain? Note that all the state-modification code becomes new-instance-construction code, which is usually more straightforward. Copying allows you to forget where a piece of data originated and avoid chain lookups as long as you only need the latest ('current') state. What am I missing? – 9000 Nov 12 '13 at 14:30
  • The various 'create loan from loan application' methods will be a pretty long list of field assignments. and it's easy to miss a field. – Ophir Yoktan Nov 12 '13 at 14:37
  • Since you maintain a link to a previous object, all data from all previous steps are available. Probably you don't (usually) need all of them on a given step, so you might want to copy only the few often-used fields. (I see how it sounds arbitrary, though.) What you copy remains an implementation detail, so it's easy to adjust without refactoring and even major rebuilding. – 9000 Nov 12 '13 at 14:48
2

When reading through your question, I heard a lot of has-a relationships. A Loan has an application. A loan has 0 or more offers. Etc, etc.

I would imagine something like this (Java pseudocode):

public class Loan {
    private Application application;
    private List<Offers> offers;
    // etc
}

In order to minimize duplication, I think I would have each of the child elements point back to the parent:

public class Application {
    private Loan parent;
    private List<Address> addresses;
    private List<Person> responsibleParties;
    private State currentState;
}

This way, elements of a Loan could navigate to related elements to grab data.

There are some definite down sides to this. For instance, if this is being stored in a database, you may be forced to load the whole Loan graph when all you want is a little bit of information. Also, some duplication is ok, and even encourage. Consider a person's address. The current address may not be the address that was used in their application. In these cases, you may want defensive copies. The application address should never change, but the current address will. It's useful to remember that parts of this are a document and that de-duplication is problematic.

0

I'd start with one object with all the shared date in it. All the other objects should have a reference to it so they can get that shared data. Further, it would have references, direct or, sometimes, indirect, to all the other objects. It could serve as the object representing all the related loans and associated documents.

Each of the other objects would contain, in addition to a reference to the shared data object, references to the other object to which they're closely related: predecessor object, successor object or objects, and anything else that might be of interest.

It should now be possible to start with any object and quickly track down all the relevant information, none of which is stored twice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.