MactoCreating The Model
Actually, starting with the model is usually a bad idea, it ties you to a particular representation of the application, usually as codified in the database schema / UML diagrams. Instead, I rather like to talk about responsibilities.
In the case of Macto, we need to figure out what the system is actually doing. It is an incarceration system, and it seems pretty clear that the root of everything in a prison is in the Inmate, right?
Not so fast!
As a matter of fact, the prison care very much about the Inmate, but Macto? Not so much. That is because we need to make a distinction between what happens in the Real World and what actions are required by our system. In the case of Macto, we are actually managing the Inmate’s Dossier. I thought about calling this a File, but I thought it would be a confusing term, considering how often we use this term technically.
Why is the Dossier so interesting? Because from a IT system perspective, it is the only thing that actually happens in a prison that can be captured inside a computer. For example, does it make sense to make a system for managing garbage removal from the cells?
Sure, if we could RFID all of the inmates, that would give us great IT experience (and save a lot of time and effort), but I am going to assume a prison where this isn’t possible, where most of the actual interactions with the inmates is actually happening by real live people. That means that what we actually care about for Macto is a fairly narrow aspect of what it means to manage a prison, the Inmate’s Dossier.
And after talking so long about why we care only about it, lets talk about what it is. The Inmate’s Dossier is the folder in the registration desk where all of the relevant information about a particular inmate is kept. Here is how it looks like:
What is stored inside that dossier? Well, all the really important aspects of being an Inmate. First and foremost, we have the chain of lawful authority for incarceration. What is that?
Let us take a very simple case, of a guy caught vandalizing a car. The chain of lawful authority for incarceration would be something like:
- 27 June 2011 20:52 – Arrest by Sargent Azulay for car vandalizing.
- 28 June 2011 14:52 – Detention, 8 days by Judge Judy
- 5 July 2011 – Remanded in Custody by Judge Thachil Oti
- 14 Aug 2011 – Sentenced, 3 months by Judge Koev Li
- 27 Sep 2011 – Released at end of sentence
What does all of this mean? Well, a lot, actually. At #1, we had a guy that was arrested by the police, we then have 24 hours to bring him in front of a judge, to make a determination about the case (a small matter of Habeas Corpus). At #2, the judge gave us 8 days to complete the investigation while the guy is still incarcerated. At #3, we showed up in front of a judge and convinced him that we have a strong enough case to keep the guy in jail until sentencing. At #4, we got the final sentence, but calculating it takes some thinking, it is a sentence from the time of the incarceration, which means that the guy spent a total of 3 months in jail, not 3 months from sentencing.
The chain of lawful authority for incarceration is incredibly important, because without it, you are Unlawfully Incarcerating and that is a Bad Thing.
Please note that I am drawing off the experience of prisons that I was at, mostly high security military prisons for terrorists. In a civilian prison, you have to worry about additional things, like work release programs, rehabilitation efforts, etc. I am not going to touch those issues in Macto, though.
What other things are going to go into the Dossier, the ability to answer quo warranto inquiries is probably the most important one, but there are other things going on there as well. For example, we track where is the Inmate located (not a trivial matter, actually). We need to track Reports on the Inmate (aggressive, suicidal, etc).
There are probably more than that, but I think that this is enough for now. You may have noticed that so far, I haven’t shown you any UML nor have I started with the database schema. To be perfectly frank, it is not relevant at this stage at all. On the next post, I’ll start talking about the basics of CRUD operations.
More posts in "Macto" series:
- (17 Aug 2011) Looking at warrants
- (15 Aug 2011) Talking to nasty people
- (11 Aug 2011) Counting is The Holy Grail
- (10 Aug 2011) Getting Started, you never forget your first Inmate
- (08 Aug 2011) The Main Screen
- (03 Aug 2011) Warrants are for fools
- (01 Aug 2011) Non functional concerns, you are a legal system
- (28 Jul 2011) And it goes on your permanent record, too!
- (27 Jul 2011) Once more from the top, I swear I had a few more over there
- (26 Jul 2011) Day to day life
- (22 Jul 2011) Where is the Inmate anyway?
- (19 Jul 2011) Let’s CREATE an Inmate
- (12 Jul 2011) Creating The Model
- (05 Jul 2011) The boundaries of a prison
- (25 Jul 2009) An end to end sample
Comments
Just out of interest, in the example given only the first two entries are recorded with times. Is that because the first entry comes with a 24 hour timeout while the others are recorded in days/months? If the guy needs to spend 3 months in jail from the time of incarceration does that mean he needs to be released at 20:52 on 27 September or is the time of release not relevant (what's another few hours right?). What happens to the Inmate Dossier when the Inmate is released? If the same guy is incarcerated to the same prison twice in his life does he get two Inmate Dossiers or are the details of both incarcerations recorded in a single Inmate Dossier? What if the guy is incarcerated in different prisons?
Mike, Those are excellent questions! Let me see if I can answer them all.
When you have a hourly warrant, it is important to match the hours. That is, at 28 June, 2011 20:53 - you are now Unlawfully Withholding Freedom. But when you don't deal with hours, you have much more latitude. You usually free someone in the morning when his Warrant run out, unless he is taken to court to renew that. You are never to hold an Inmate past the Warrant. Well, never is a harsh term, you don't do that unless there is something really strange going on.
In this case, the guy would probably walk out of the prison on 27th Sept 2011, around 9 - 10, the exact hour doesn't really matter, as long as it before midnight. That said, you have better have a good explanation for that if you release him on midnight.
In some cases, we have taken an Inmate whose warrant run out but wasn't released for some reason (and couldn't be released due to the time) and put him on the Staff Quarters, to make it explicit that he is not incarcerated any longer. He was released, and simply had no where to go on midnight.
After an Inmate is released (also when he is transferred out), the Dossier is Archived. If the Inmate goes back to prison, we Reactivate the Dossier. Note that it is known that sometimes we won't find the old Dossier (different spelling for the name, arrived with no id, etc), so we will have a new Dossier for the same person. A single Dossier can thus contain multiple Incarcerations. To make things more confusing, Incarcerations can overlap, partially overlap or be served one after another.
When an Inmate is Transferred to a different prison, his Dossier is Archived, a copy goes with him to the other prison, but Macto isn't meant to be a cross prison system, it is local to a single prison.
Stuff like Inmate Id, for example, are all local to the prison and are not shared.
I guess Guantanamo's IT guys fucked up the part about "the chain of lawful authority for incarceration".
I like the approach. Developers are often too quick to get technical and end up modelling their view of the problem, not the actual business processes involved. I reckon 90% would've created an Inmate class (probably an IInmateRepository and IInmateService too).
@Ayende You said you have been in a prison - I presume as a guard/auxiliary and not as an inmate ;)... was this period of time as a compulsory IDF serving time? I mean, as far as I know, any Israeli citizen (man or woman) must serve either as a military, either as an auxiliary (I don't know exactly the offical term, - is this true? Have you study krav maga combat style while serving there? Sorry if this is not the place to ask these questions, I am just curious since you have mentioned in one of your older posts that you have done some programming while serving ...
Bodgan, You probably want to read this: http://ayende.com/blog/539/leave-to-live-by-no-mans-leave
@Ayende Really interesting experience you got there ... :)
I had been wondering why you chose a prison incarceration system, and seeing your reference to the earlier blog entry, I now understand why.
However, do you think that you have unfair domain knowledge that is guiding your analysis and design? I wonder how your analysis (and subsequent design) would proceed without that insider knowledge? How would you design given that you are not in possession of all the "business" facts?
I know this is just a sample app you are building, and these questions are beyond the scope of this series of articles, but most devs end up working in business domains that they have little experience in, and that is the reason poor design decisions are made
@Pete
From what I understand of DDD you should always have a Domain Expert in order to figure out the domain (aka business facts). Together with the domain expert you create the design. In fact, in the ideal case the expert should even be able to spot logical errors in the source code.
In the case of Macto it didn't take Ayende very long to find a domain expert. ;)
When visiting http://ayende.com/blog/539/leave-to-live-by-no-mans-leave I received the following error message:
Object reference not set to an instance of an object. System.NullReferenceException: Object reference not set to an instance of an object. at System.Collections.Specialized.NameObjectCollectionBase.BaseGetKey(Int32 index) at System.Collections.Specialized.NameValueCollection.Add(NameValueCollection c) at Raven.Client.Connection.HttpJsonRequestFactory.GetCachedResponse(HttpJsonRequest httpJsonRequest) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\HttpJsonRequestFactory.cs:line 164 at Raven.Client.Connection.HttpJsonRequest.ReadStringInternal(Func
1 getResponse) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\HttpJsonRequest.cs:line 171 at Raven.Client.Connection.HttpJsonRequest.ReadResponseString() in C:\Work\ravendb\Raven.Client.Lightweight\Connection\HttpJsonRequest.cs:line 131 at Raven.Client.Connection.ServerClient.DirectQuery(String index, IndexQuery query, String operationUrl, String[] includes) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\ServerClient.cs:line 693 at Raven.Client.Connection.ServerClient.<>c__DisplayClass24.<Query>b__23(String u) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\ServerClient.cs:line 677 at Raven.Client.Connection.ServerClient.TryOperation[T](Func
2 operation, String operationUrl, Boolean avoidThrowing, T& result) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\ServerClient.cs:line 169 at Raven.Client.Connection.ServerClient.ExecuteWithReplication[T](String method, Func2 operation) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\ServerClient.cs:line 139 at Raven.Client.Connection.ServerClient.Query(String index, IndexQuery query, String[] includes) in C:\Work\ravendb\Raven.Client.Lightweight\Connection\ServerClient.cs:line 677 at Raven.Client.Document.AbstractDocumentQuery
2.GetQueryResult() in C:\Work\ravendb\Raven.Client.Lightweight\Document\AbstractDocumentQuery.cs:line 1321 at Raven.Client.Document.AbstractDocumentQuery2.get_QueryResult() in C:\Work\ravendb\Raven.Client.Lightweight\Document\AbstractDocumentQuery.cs:line 380 at Raven.Client.Linq.RavenQueryProviderProcessor
1.ExecuteQueryTProjection in C:\Work\ravendb\Raven.Client.Lightweight\Linq\RavenQueryProviderProcessor.cs:line 1035 at Raven.Client.Linq.RavenQueryProviderProcessor1.Execute(Expression expression) in C:\Work\ravendb\Raven.Client.Lightweight\Linq\RavenQueryProviderProcessor.cs:line 1021 at Raven.Client.Linq.DynamicRavenQueryProvider
1.Execute(Expression expression) in C:\Work\ravendb\Raven.Client.Lightweight\Linq\DynamicRavenQueryProvider.cs:line 145 at Raven.Client.Linq.DynamicRavenQueryProvider1.System.Linq.IQueryProvider.Execute(Expression expression) in C:\Work\ravendb\Raven.Client.Lightweight\Linq\DynamicRavenQueryProvider.cs:line 208 at Raven.Client.Linq.RavenQueryInspector
1.GetEnumerator() in C:\Work\ravendb\Raven.Client.Lightweight\Linq\RavenQueryInspector.cs:line 93 at System.Collections.Generic.List1..ctor(IEnumerable
1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at RaccoonBlog.Web.Controllers.SectionController.List() in C:\Work\RaccoonBlog\src\RaccoonBlog.Web\Controllers\SectionController.cs:line 42 at lambda_method(Closure , ControllerBase , Object[] ) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary
2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func
1 continuation) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func1 continuation) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func
1 continuation) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList1 filters, ActionDescriptor actionDescriptor, IDictionary
2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)Pete, I am not the one doing most of the work here, I am the domain expert
Tim, Thanks for reporting this, it has been fixed in RavenDB and will go live soon
@Ayende @Patrick so as a "domain expert", the problem domain is described in the blog post - but it seems that Ayende is proposing a literal implementation of the problem domain in the solution: "Dossier" rather than "Inmate" as the main example
It seems that a novice developer would focus on the literal; a journeyman would propose the "inmate" model (having been polluted with "best practice" and "guidance"; and finally to become master, we must see the literal again.
Looking forward to the rest of the series
Does it really matter if the domain model accurately describes the reality behind bars? It's supposed to be a technology demo application so the problem domain can be a total fiction, it should only be consistent and nontrivial (but then Ayende wouldn't have a chance to tell these great stories about his work in prison)
@Rafal, you don't get it - it's not intended to be a technology demo, even though it uses technology. It's goal is to be an approach demo: how to use DDD (which isn't a technology but a mindset and a method) to solve a complex business problem, how to work with the customer / domain expert to build a viable model for a real-world needs, and only then how to use technology to shape that knowledge into a working software.
So the problem domain is the key here, and technology - only a tool to support it. Like it should be in a real life. Like it wasn't in the case of the recently reviewed showcase app from microsoft (which was exactly that - a technology demo without any meaning, sense and justification for DDD approach, unfortunately lacking in the technology department as well).
Where is the source info for the dossier coming from ? Does it need to be uploaded from \ cross checked against a 1970's style mainframe for example ? What are the integration points that expand the example beyond CRUD ? Or is that V2 :)
@Rafal - having just recently gone through the process of building a demo it is quite difficult to come up with a demo using the total fiction approach. Fiction usually follows the happy path. Real systems are non-fiction, 60-80% of the effort comes from dealing with exceptions, edge cases, the legacy of the past etc.
Adrian, The source is usually physical paperwork. No cross checks. No integration right now.b
Isn't this what a basic usecase model (in UML) would capture? I usually like to start there myself.
Ayende,
Off-Topic, but the name "Ayende Rahien" in your comments links to the wrong URL "../blog/blog"
Sony, And now you force a techo centric approach for the business to work with. It is like starting the days by putting on the blinders.
I can't see what's wrong with calling it Inmate. Isn't it, afterall, what a Dossier represents? It's like an HR application calling its employee EmployeeDossier or EmployeeData, because technically speaking, the company cares about its employees, but an HR system itself does not. (An employee may be sick on his Dossier, but who knows where the actual Employee is in the real life, . Also, when you're hiring a new employee, its only the dossier that ever enters the HR office, not the employee). Does it mean calling it Employee (and the term "create employee") is wrong?
Or similarly a car-service-station app that calls its entity CarDocument instead of Car. Or a library system that calls BookRecord instead of Book. Or an inventory system that calls "RackData" instead of just Rack.
You can call it dossier, record, file, data, documentation, figures, etc to make a distinction from the actual real-world entity.. but isn't it what "domain-model" means in DDD? Chapter one of the blue DDD book specifically points this out at length. Domain model is like the world-map: it's merely "one way" to describe the actual thing in the real-world. It's never meant to be accurate. Domain-model must serve as a subjective representation of the entity from the perspective of the system, not the actual world. Furthermore, there can be many ways you can look at the same elephant (the same way you have multiple ways to see an inmate), even within one single application, which is why you have bounded-contexts.
I'm not saying it has to be called Inmate, rather than Dossier. It's perfectly valid to argue that Dossier makes the domain clearer. But I disagree that calling Inmate would be a mistake either, at least not just because it's an inaccurate real-world representation
Hendry, Except that we actually have a different notion of an Inmate. When you hear people speaking, they make a big distinction between the Inmate and his Dossier. They are considered to be very different things by the actual users of the system.
Comment preview