Summary:
Object-oriented programming was supposed to unify the perspectives of the programmer and the end user in computer code: a boon both to usability and program comprehension. While objects capture structure well, they fail to capture system action. DCI is a vision to capture the end user cognitive model of roles and interactions between them.
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: January 7, 2012 3:19 AM by
|
I find the example given to have a contrived feeling about it. There is nothing non-OO about a funds transfer. A funds transfer is a great class to have. More importantly, it is the sort of thing likely to be persisted to a database. While I agree with the idea that the accounts take on the "roles" of source and destination, it is quite likely that any account will contain protocol to implement either role and failing this will contain minimal protocol that will allow a wrapping adaptor to make fulfilling the role straight forward and obvious.
So much for examples. OTOH, I agree that there are certain interactions that defy good OO design practice. Specifically, business rules and constraints. These rules typically capture interactions which defy all reasonable ideas of locality of reference (thank you - legislators). This is where pattern matching rules engines like ObjectiveCLIPS (http::/objectiveclips.com), JESS, CLIPS, Rete++, and similar products can save the day.
|
|
|
> But a Source_Account isn't really a "thing" like an > Account is, it's a way to use a "thing". So > Savings_Account IS an Account (inherits from), but > Source_Account is a WAY TO USE an Account (contains > pointer to).
Yes, it is a way to use an Account and nothing else. It extends specifically functionality of an Account; it is an Account plus something. I think inheritance expresses this profound relationship more clearly than embedding a pointer to the 'thing'.
IMO the difference is only in the communication of intent, both ways are otherwise equally usable.
|
|
|
> > But a Source_Account isn't really a "thing" like an > > Account is, it's a way to use a "thing". So > > Savings_Account IS an Account (inherits from), but > > Source_Account is a WAY TO USE an Account (contains > > pointer to). > > Yes, it is a way to use an Account and nothing > else. It extends specifically functionality of an > Account; it is an Account plus something. I think > inheritance expresses this profound relationship more > clearly than embedding a pointer to the 'thing'. > > IMO the difference is only in the communication of intent, > both ways are otherwise equally usable.
You are missing so many subtleties here it is hard to figure out how to nail them down to you.
Design is subtle.
We define objects to describe a domain. They are peers.
The experienced programmers here are trying to convey two things: (1) TransferSlip is your domain object, not Source_Account. Source versus destination are parameters. You gain no fidelity in your domain representation by making them first class objects. (2) The danger comes in not making your transaction interface idempotent. Even if your client and service are in the same trust boundary (which would never be the case in this example), you want some notion of a scoped guard once-and-only-once guarantee.
|
|
|
> (1) TransferSlip is your domain object, not > Source_Account. Source versus destination are parameters. > You gain no fidelity in your domain representation by > y making them first class objects.
That is the point you seem to be missing - they are only some parameters for you, but the DCI says they are concepts on their own within given Context.
The Context forms a subdomain (albeit a small one) and the roles are its domain objects, extending actors (parameters) with features which make sense only within this Context, so the 'more basic' domain objects are not cluttered with them.
> (2) The danger comes in not making your transaction > interface idempotent.
I think we are discussing something else here.
|
|
|
> > That is the point you seem to be missing - they are only > some parameters for you, but the DCI says they are > concepts on their own within given Context.
I'm not missing the point. What do you think the responsibility of a TransferSlip is? It instantiates those contextual relationships. It also replaces Jim/Trygve's "System" actor. It becomes trivial to model a TransferSlip as a view, too. Why? B/c it's proper OO.
> The Context forms a subdomain (albeit a small one) and the > roles are its domain objects, extending actors > (parameters) with features which make sense only within > this Context, so the 'more basic' domain objects are not > cluttered with them.
Design is subtle. Jim/Trygve's solution greatly increases artificial consistency - that is why they refer to DCI + MVC. The small size of their solution tricks you into thinking it is good.
Note: Traits are still a great idea, but still no silver bullet.
> > (2) The danger comes in not making your transaction > > interface idempotent. > > I think we are discussing something else here.
We're talking about state machines versus "DCI". A proper state machine has scoped guards and once-and-only-once guarantees (and a no-throw guarantee).
|
|
|
Can we remove all the dynamic aspects and start with a static implementation in plain Java. From there we can explore the advantage and possibilities of more dynamic approaches.
|
|
|
I'm having a significant problem seeing what's different in this approach than the approach advocated by, among others, Fowler and Cockburn(1). They advocate a separate layer between the GUI and the domain - this has been called the Application or the Process or Procedure layer by different authors. To take the example of a funds transfer between accounts: the domain would include the various kinds of account objects as well as a FundsTransfer object. The latter object is needed because it's the transaction log, the source for the bank statement and the line entry in the bank's accounts. When the logged-in customer presses the "transfer money between accounts" button, the ATM GUI creates the ATMFundsTransfer object. The ATMFundsTransfer object then creates the domain FundsTransfer object with the amount, the source account number and the recipient account number, and it interprets the result (done or insufficient funds) back to the GUI. This matches the mental model (or at least my mental model) of how a bank transaction is normally done. John Roth (1) http://alistair.cockburn.us/Hexagonal+architecture
|
|
|
@ (1) http://alistair.cockburn.us/Hexagonal+architectureI came across this years ago on the c2 wiki, and feel the same about it today that I do now. @ They advocate a separate layer between the GUI and the domain All this stuff has a common theme. No code. No proof of clear thinking, At least drawing out a collaboration diagram, class diagram, etc. Discussing things in terms of variations of canonical GoF diagrams would help, as well. Furthermore, none of these "architectures" actually give guidance on partitioning your development team and therefore choosing how to split up the gross application structure such that the end-results of multiple teams can be seamlessly integrated. They also don't reflect real world realities, such as how services are allowed to communicate with the client. For instance, is your application request/response driven? If so, why? Are you writing a batch compiler that has to build Windows 7 source code? If so, then non-interactive fits your requirements. In the compiler marketplace, interactivity would create overhead (slowness) and would be negligent design. Are you writing a web application? If so, then how do you build an event-driven model on top of the web's inherent request/response driven model? How do you manage memory across tiers and layers? Do you just stick all memory ever requested into the HTTP Session object until the session expires? Teaching programmers to think is a scary idea, because most people lack the ability to think new thoughts... but it is more likely to solve real world problems than draping buzzword-compliant mega-patterns over your design documents. Sometimes vague ideas are good, other times they are mostly bad and irritating. In Society of Mind, Marvin Minsky has a chapter dedicated to his famous paper on programming "frames". He points out that his real contribution was that he was specific enough to give people ideas of their own, but vague enough to allow room for interpretation and creative applications.
|
|
|
@Trygve > The first chapter preprint documents a working Bank > transfer program. You find it at > http://heim.ifi.uio.no/~trygver/2009/bb5bank.pdfQuote: @The Context bind roles to objects upon instantiation so that TransferMoneySource has been bound to the appropriate account when the execution gets to this point. This is totally wrong. You are doing compile-the-world procedural programming. You're also strongly typing it to give the impression it's rock-solid design. Rejoice, though. I'm sure there are still some Java programmers who use EJBs who can't tell the difference. With a TransferSlip (as I've stated many times here as the right approach), you let the user determine the execution. There is no "this point" guarantee. In fact, when you display a TransferSlip on screen, the source has yet to even be instantiated. This gives you a totally different look at the world, and it's called OO.
|
|
|
> Can we remove all the dynamic aspects and start with a > static implementation in plain Java. From there we can > explore the advantage and possibilities of more dynamic > approaches. I have been busy so it took a while. Sorry. In my latest post there are two versions of the account example in Java: One without traits and one with traits. The examples are taken from Jim Copliens book draft. http://www.jroller.com/sebastianKuebeck/entry/object_oriented_programming_2_0To Trygve Reenskaug and Jim Coplien: Keep up the great work! No matter what some comments babble. You cannot please everyone :-)
|
|
|
@No matter what some comments babble. You cannot please everyone :-) It's not about pleasing. It is about not using strawman's to say OO doesn't work. http://www.jroller.com/sebastianKuebeck/entry/object_oriented_programming_2_0@As you can see, DCI helps to increase cohesion in object models while remaining it understandable. It introduces additional flexibility and solves problems that would cause nasty workarounds otherwise. Judging by this example, it seems you choose to ignore (or simply don't understand) what the debate is even about. DESCRIBE THE PROBLEM YOU CLAIM CAUSES "NASTY WORKAROUNDS". Back up your claim. Show me the pain I supposedly experience today, and why I should convert to your religion. Bootstrap your example with a GUI. Connect DCI to MVC. Let the fun begin.
|
|
|
Just to zero this in... in case people still don't get it...
Jim said in his article: @The MVC framework makes it possible for the user to reason about what the system is: the thinking part of the user cognitive model. But there is little in object orientation, and really nothing in MVC, that helps the developer capture doing in the code.
Jim says MVC is a flawed architecture. I agree.
Where we differ is on this myth that you should add DCI on top of MVC to fix the problem. Jim likes the idea of using his DCI to patch MVC. I don't. Instead, I prefer to create truly object-oriented user interfaces.
But why do I think Jim is heading in the wrong direction? Is it merely accidental complexity at the architecture level? NO! The complexity actually boils down to his object model codified in his use cases.
His example gave the following use case: 1. Account holder chooses to transfer money from one account to another 2. System displays valid accounts 3. User selects Source Account 4. System displays remaining valid accounts 5. Account holder selects Destination Account 6. System requests amount 7. Account holder inputs amount 8. Move Transferred Money and Do Accounting
The entity in that use case that clearly doesn't belong is the System object. In proper OO, that is a TransferSlip (and for another use case it is WithdrawalSlip, another use case it is DepositSlip). The TransferSlip replaces steps 2, 4 and 6; it replaces the "System display" actor.
Are any of you disagreeing with my decision to do this? If so, why do you think it hurts the clarity of the code? I really want to know.
|
|
|
Thanks Sebastian. Very helpful.
|
|
|
> It's not about pleasing. It is about not using strawman's to say OO doesn't work.
On the contrary. Programming paradigms are exchangeable by definition. There is no right or wrong as you can choose any paradigm you like to get working software. It is an inherently irrational choice. So if you take "OO fails to capture behavior" literally and out of the context, you are right that this claim is exaggerated.
About my claim: > It introduces additional flexibility and solves problems that would cause nasty workarounds otherwise.
You are right. You can find good solutions (using pure OOP or whatever) for that problem without using DCI.
|
|
|
I have put new section preprint on my DCI page for your enjoyment. The section describes an activity planning program that combines DCI and MVC. It is still a toy program, but closer to reality than previous examples. I have implemened two versions; one with DCI and one without. The two versions have been made as similar as possible to expose what DCI does to a program. The answer is that it organizes the code differently so that the programmer's mental model is different. The article is at http://heim.ifi.uio.no/~trygver/2009/bb4plan.pdfmy DCI home page is at http://heim.ifi.uio.no/~trygver/themes/babyide/babyide-index.html
|
|