Ruby Forum Ruby > "Code must be Chunkable"

Posted by Thomas Sawyer (7rans)
on 09.02.2010 00:44
(Received via mailing list)
I watched Part 1 of this great lecture, and I just had to share:

  http://architects.dzone.com/videos/dci-architecture-trygve

You can read my brief post on it here:

  http://proutils.github.com/2010/02/dci-architecture/index.html

I love the line "Code must be Chunkable". Reminds me of _why.

Also some interesting counter arguments about TDD.
Posted by Brian Candler (candlerb)
on 09.02.2010 17:40
Thomas Sawyer wrote:
>   http://architects.dzone.com/videos/dci-architecture-trygve

Interesting.

Part 2 explores some ideas in Ruby with a simple bank transfer example. 
What I don't get is why you'd want to inject the logic of transferring 
money between two accounts into one of the accounts and then call it 
there. Surely you could just do it all in the context object itself? In 
that case, the transfer-money context would just become what I'd call a 
'controller'.

So I'd find it useful to see a more extensive example which shows the 
benefits of working this way.

Then at the end, it says that an account isn't really an object at all - 
but all the previous code has shown it as a concrete object (e.g. 
Account.find(id)). So an example of what an account role *should* look 
like in code would be good.
Posted by Thomas Sawyer (7rans)
on 11.02.2010 09:29
(Received via mailing list)
On Feb 9, 11:40 am, Brian Candler <b.cand...@pobox.com> wrote:
> 'controller'.
>
> So I'd find it useful to see a more extensive example which shows the
> benefits of working this way.

I just finished watching the 2nd video. I agree with you. Coplien does
an awful job of explaining things. Trygve, despite his age, does a
much better job.

> Then at the end, it says that an account isn't really an object at all -
> but all the previous code has shown it as a concrete object (e.g.
> Account.find(id)). So an example of what an account role *should* look
> like in code would be good.

I don't know what he is talking about. It's as if he thinks, if
something isn't solid it isn't an object. And his whole speel about
logging-in is not a usecase because there's no business goal, is silly
too. He's splitting hairs over words and as much as he thinks DCI is
so cool, I'm not sure he actually "gets it" himself. However, at the
very beginning he does point out the main point of the whole pursuit
-- code readability.

His Ruby code, btw, wasn't very well written, would not run and worse,
I don't think represents DCI well either. So I threw together a fix
that I think represents it at least a little better. Still a simple
bank transfer, but it works, so that in it's self is an
improvement ;)

One thing I would point out, Coplien's TransferMoneyContext is a
Command pattern --a class that encapsulates a single action. I don't
think it's necessary to go that far. While my example follows his, if
I were doing it otherwise, I would probably make it an
AccountInteractions class and define methods within it for all the
ways in which two accounts could interact.

  #
  class Account
    # simple account db
    def self.accounts
      @@accounts ||= {}
     end

    def self.find(accountID)
      accounts[accountID]
    end

    attr :accountID
    attr :balance

    def initialize(accountID, initialBalance)
      Account.accounts[accountID] = self

      @accountID = accountID
      @balance = initialBalance
    end
  end

  #
  class SavingsAccount < Account
    def initialize(accountID, initialBalance)
      super(accountID, initialBalance)
    end

    def availableBalance; @balance; end
    def decreaseBalance(amount); @balance -= amount; end
    def increaseBalance(amount); @balance += amount; end

    def updateLog(message, time, amount)
      puts "%s %s #%s $%.2f" % [message, time, accountID, amount.to_f]
    end
  end

  # Use Case (Context)
  class MoneyTransfer
    attr :amount
    attr :source_account
    attr :destination_account

    def initialize(amt, sourceID, destID)
      @amount = amt
      @source_account = Account.find(sourceID)
      @destination_account = Account.find(destID)
    end

    def execute
      source_account.extend TransferSource
      destination_account.extend TransferDestination

      source_account.withdraw(amount)
      destination_account.deposit(amount)

      #source_account.unextend TransferSource
      #destination_account.unextend TransferDestination
    end
  end

  # Account Role
  module TransferSource
    def withdraw(amount)
      raise "Insufficiant Funds" if balance < amount
      decreaseBalance(amount)
      updateLog "Transfer Out", Time.now, amount
    end
  end

  # Account Role
  module TransferDestination
    def deposit(amount)
      increaseBalance(amount)
      updateLog "Transfer In", Time.now, amount
    end
  end

  # try it out

  SavingsAccount.new(1, 500)
  SavingsAccount.new(2, 100)

  transfer_case = MoneyTransfer.new(50, 1, 2)
  transfer_case.execute


Notice the remarked #unextend lines. For a real implementation of DCI,
we would want to remove these roles once we used them, but Ruby's
extend doesn't allow that, of course.

So the bottom line I think is this. You work out usecases (i.e.
contexts) for actually doing things. You make your objects pretty dumb
--primarily state bags. You figure out the roles your objects must
play to satisfy those use cases and code those. Then you code the
usecases with the roles and objects so as to get the job done. The
whole programs then becomes easier to read b/c you are reading
usecases first,  which explains things as the interaction of roles
played by simple objects. And presto the "Code is Chunkable".

(P.S. I also think this is much more like AOP then Coplien is willing
to admit.)
Posted by Brian Candler (candlerb)
on 11.02.2010 10:41
Thomas Sawyer wrote:
>     def execute
>       source_account.extend TransferSource
>       destination_account.extend TransferDestination
> 
>       source_account.withdraw(amount)
>       destination_account.deposit(amount)
> 
>       #source_account.unextend TransferSource
>       #destination_account.unextend TransferDestination
>     end
>   end

Thank you. That was pretty much what I was thinking. After all, in a 
real bank transfer, the "source account" isn't responsible for carrying 
out the transfer, the bank clerk is.

In a play, there's a single script. And if either Romeo or Juliet 
forgets their lines, it's the prompter at the front of the stage who 
tells them what to say next. (OK, perhaps that's taking the analogy too 
far :-)

I can see a specific case where this context/role split would work well. 
In Rails-type apps, I've wondered before how best to implement logic 
which clearly belongs in the model, but which is affected by properties 
of the controller. Behaviour dependent on the user's timezone preference 
is one example; adding updated_by and updated_ip stamps is another.

Rails solves the timezone problem by just stuffing it into a 
thread-local variable, which is horrible.

Having a 'context' object available to the model at execution time makes 
total sense. And as long as you inject the context at the same time as 
you inject the methods which make use of that context, then you know the 
two are aligned; it's safe because you know that code can't be used 
elsewhere.

In practice this might mean you eschew the model's own 'save' method in 
favour of a ModelUpdater context and a UpdatableModel role.
Posted by Brian Candler (candlerb)
on 11.02.2010 10:45
Thomas Sawyer wrote:
> Coplien does
> an awful job of explaining things. Trygve, despite his age, does a
> much better job.

I'd say "Trygve, because of his age, does a much better job" :-)

(I also started by toggling in binary machine-code. Admittedly that was 
switches and LEDs rather than switches and lamps)
Posted by Michel Demazure (badal)
on 11.02.2010 15:17
Thomas Sawyer wrote:
> 
> Notice the remarked #unextend lines. For a real implementation of DCI,
> we would want to remove these roles once we used them, but Ruby's
> extend doesn't allow that, of course.
> 

Could you not extend again by a Module which would undefine the added 
methods ?
Posted by Thomas Sawyer (7rans)
on 11.02.2010 15:23
(Received via mailing list)
On Feb 11, 4:45 am, Brian Candler <b.cand...@pobox.com> wrote:
> Thomas Sawyer wrote:
> > Coplien does
> > an awful job of explaining things. Trygve, despite his age, does a
> > much better job.
>
> I'd say "Trygve, because of his age, does a much better job" :-)

Good point. I agree.
Posted by Brian Candler (candlerb)
on 11.02.2010 17:28
Michel Demazure wrote:
> Could you not extend again by a Module which would undefine the added 
> methods ?

It's a moot point in the common case where objects don't persist (i.e. 
Account.find(id) creates a new object from info in the database)

I think it could be done more cleanly with a facade/proxy object. This 
would have an added advantage that concrete methods in the underlying 
object could not call back to the context (which they should not be able 
to do; only the injected methods should do this)
Posted by Michel Demazure (badal)
on 11.02.2010 18:57
Brian Candler wrote:
> Michel Demazure wrote:
>> Could you not extend again by a Module which would undefine the added 
>> methods ?
> 
> It's a moot point in the common case where objects don't persist (i.e. 
> Account.find(id) creates a new object from info in the database)
> 
> I think it could be done more cleanly with a facade/proxy object. This 
> would have an added advantage that concrete methods in the underlying 
> object could not call back to the context (which they should not be able 
> to do; only the injected methods should do this)

I agree.
M.
Posted by Thomas Sawyer (7rans)
on 11.02.2010 21:39
(Received via mailing list)
On Feb 11, 11:29 am, Brian Candler <b.cand...@pobox.com> wrote:
> It's a moot point in the common case where objects don't persist (i.e.
> Account.find(id) creates a new object from info in the database)
>
> I think it could be done more cleanly with a facade/proxy object. This
> would have an added advantage that concrete methods in the underlying
> object could not call back to the context (which they should not be able
> to do; only the injected methods should do this)

I played around with the concepts a bit more. You can see what I came
up with here:

  http://gist.github.com/301909

I did a couple of interesting things (though I suppose I may be taking
it too far) I thought of a Context as a Scene in a play, in which I
defined the roles upfront (ie. at the class level) -- I use the Anise
gem to do this, btw.  And, despite what was said in the lecture, I was
able to use polymorphism with regard to the roles. This approach seems
very interesting. I was able to define two methods of the same name
that can act on the same object, but dependent on the role it plays.
Thus the Context has a method that is dispatched to all the roles.
While my code is from perfect the approach itself does seem like it
could be useful for large applications. (It feels like overkill for
small libraries though).
Posted by Brian Candler (candlerb)
on 11.02.2010 22:51
> I was able to define two methods of the same name
> that can act on the same object, but dependent on the role it plays.

I like that. Your base class Role is exactly what I was thinking of as a 
proxy.

> Thus the Context has a method that is dispatched to all the roles.

Hmm, that's very clever, but it's a bit too magic for me. It's 
multicasting (pun not intended); I'd probably just iterate in the 
context to make it explicit.
Posted by Brian Candler (candlerb)
on 11.02.2010 23:07
Here's a noddy version (minus annotations)

http://gist.github.com/302016
Posted by Thomas Sawyer (7rans)
on 12.02.2010 02:34
(Received via mailing list)
On Feb 11, 5:07 pm, Brian Candler <b.cand...@pobox.com> wrote:
> Here's a noddy version (minus annotations)
>
> http://gist.github.com/302016

Very nice --very clean. That close to how first thought about it too,
but some of those other ideas came to mind in the processes and I
wanted to experiment with them to see how they would play out.

I think you are right that the "role dispatching" is too magic. I like
it in the sense that it feels like a natural fit for concurrent
processing. However, at the very least, there needs to be a way to do
it explicitly as you have done.

The class level casting on the other hand, I am finding very
appealing. The reason being that it provides a very natural limiting
structure to scope of a context, i.e. one role per attribute per
context. By casting at the instance level, a context can do anything
whatsoever, each method could take actions completely unrelated. But
having the casting the at the class level ensures the methods will
have a interrelated coherence.
Posted by Jörg W Mittag (Guest)
on 13.02.2010 01:00
(Received via mailing list)
Brian Candler wrote:
> Thomas Sawyer wrote:
>>   http://architects.dzone.com/videos/dci-architecture-trygve
> [...]
> Then at the end, it says that an account isn't really an object at all - 
> but all the previous code has shown it as a concrete object (e.g. 
> Account.find(id)). So an example of what an account role *should* look 
> like in code would be good.

I have been following DCI on and off ever since James's JAOO 2008
interview and more closely since James's and Trygve's March 2009
article. I won't even try and pretend that I understand as little as
1% of this stuff, but there is one important idea that I have carried
around with me, ever since I read all those "it's just traits"
comments on the Artima article: one thing that I always need to remind
myself of, is that doing DCI in Ruby is like doing OO in C: it's only
a *very* rough approximation which lacks much of the expressive power
and often confuses the idea with the implementation.

Whenever I think "it's just traits/aspects/mixins/responsibilities and
why does he say this isn't an object when it clearly is?" I picture
myself trying to explain OO to a C programmer, in C, and constantly
answering questions like "it's just structs and function pointers and
why do you keep calling it an object when it clearly is a struct?" and
yelling back at him "because there are no objects in C, idiot, structs
is all I have!"

I believe that, like OO or logic programming, DCI is only going to
start to *really* shine (or, as the case may be, bomb spectacularly)
when we have DCI languages. There were many logic systems in Lisp
before Prolog, and as Alan Kay recently pointed out, there were object
systems in assembly going back as far as 1952, but before Prolog,
Simula and Smalltalk nobody cared, and nobody understood. It's hard to
see the real value of the idea behind the implementation, if the
implementation leaks all over the place as structs+function pointers
as objects and methods do in C and objects, classes and mixins as
data, context and roles do in Ruby.

Unfortunately, for this dynamic role injection stuff, we run into one
of the (very few) limitations of Ruby. We cannot just, as Trygve says,
"subclass the compiler" and "add to and delete methods from the method
dictionary" in Ruby (although we probably *can* in Rubinius) like
Trygve's Squeak implementation does or subvert the compiler like
James's C++ template metaprogramming implementation does.

Ironically, this stuff, which looks like a match made in heaven for
Ruby, is one of the *very few* instances where C++'s static
metaprogramming outshines Ruby's dynamic metaprogramming and the leaky
abstraction of ECMAScript actually *helps* rather than hurts.
(Although I *do* have a seed of a spark of a hunch on how to fake
dynamic class composition.)

Anyway, I don't really have anything useful to contribute to this
discussion other than the tip that it helps to constantly remind
myself that DCI in a non-DCI language is always only an approximation.

jwm
Posted by Jörg W Mittag (Guest)
on 13.02.2010 01:35
(Received via mailing list)
Jörg W Mittag wrote:
> [...]
> I believe that, like OO or logic programming, DCI is only going to
> start to *really* shine (or, as the case may be, bomb spectacularly)
> when we have DCI languages.

BTW: I *do* realize that this contradicts what James and Trygve have
been saying, that DCI is a paradigm that enables "good OO" in
*existing mainstream* languages.

jwm
Posted by Michel Demazure (badal)
on 13.02.2010 09:42
Jörg W Mittag wrote:
> Jörg W Mittag wrote:
>> [...]
>> I believe that, like OO or logic programming, DCI is only going to
>> start to *really* shine (or, as the case may be, bomb spectacularly)
>> when we have DCI languages.
> 
> BTW: I *do* realize that this contradicts what James and Trygve have
> been saying, that DCI is a paradigm that enables "good OO" in
> *existing mainstream* languages.
> 
> jwm

I am not familiar enough with the DCI paradigm. But from times to times, 
I feel that Ruby does not go far enough with duck typing. Modules are 
not really objects ("everything is an object", they say), but a way to 
assign methods to objects "from outside".

Yes, but you can quack like a duck ("include duck"), then miauw like a 
cat ("include cat"), but you cannot come back to quacking. "Once a duck, 
always a duck !", ODAD !

Is there a deep reason forbidding a more clever dispatching allowing to 
de-include modules and/or re-include modules ?

md
Posted by Michel Demazure (badal)
on 13.02.2010 10:24
Michel Demazure wrote:

> 
> Is there a deep reason forbidding a more clever dispatching allowing to 
> de-include modules and/or re-include modules ?
> 

This would avoid the use of ad-hoc classes or singletons to disguise 
modules.

md
Posted by Ryan Davis (Guest)
on 13.02.2010 11:27
(Received via mailing list)
On Feb 13, 2010, at 00:42 , Michel Demazure wrote:

> Modules are 
> not really objects ("everything is an object", they say), but a way to 
> assign methods to objects "from outside".

how are modules not objects? do they not have state? do they not have 
behavior? are they not instances of a class?

> Is there a deep reason forbidding a more clever dispatching allowing to 
> de-include modules and/or re-include modules ?

the 'un' gem enables this.
Posted by Michel Demazure (badal)
on 13.02.2010 11:37
Ryan Davis wrote:
> On Feb 13, 2010, at 00:42 , Michel Demazure wrote:
> 
>> Modules are 
>> not really objects ("everything is an object", they say), but a way to 
>> assign methods to objects "from outside".
> 
> how are modules not objects? do they not have state? do they not have 
> behavior? are they not instances of a class?

In that broad sense yes. But ...

>> Is there a deep reason forbidding a more clever dispatching allowing to 
>> de-include modules and/or re-include modules ?
> 
> the 'un' gem enables this.

Thanks, I'll try it.

md
Posted by Michel Demazure (badal)
on 13.02.2010 11:45
Michel Demazure wrote:
> Ryan Davis wrote:

>> the 'un' gem enables this.
> 
> Thanks, I'll try it.
> 
> md

Where do I find it ? Thks.
Posted by Rick Denatale (rdenatale)
on 13.02.2010 14:41
(Received via mailing list)
On Sat, Feb 13, 2010 at 5:27 AM, Ryan Davis <ryand-ruby@zenspider.com> 
wrote:
>
> On Feb 13, 2010, at 00:42 , Michel Demazure wrote:
>
>> Modules are
>> not really objects ("everything is an object", they say), but a way to
>> assign methods to objects "from outside".
>
> how are modules not objects? do they not have state? do they not have behavior? are they not instances of a class?

If you prick them, do they not bleed? <G>

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
Posted by Colin Bartlett (Guest)
on 13.02.2010 16:01
(Received via mailing list)
On Sat, Feb 13, 2010 at 1:40 PM, Rick DeNatale <rick.denatale@gmail.com> 
wrote:
> If you prick them, do they not bleed? <G>
>
> --
> Rick DeNatale

I just read Rick's one-liner sitting - appropriately - in the cafe/bar
of the ICA (Institute of Contemporary Arts) in London, and it's made
my afternoon, even if I don't get to see the Japanese film for which
I'm third on a waiting list!
Posted by David Masover (Guest)
on 13.02.2010 19:07
(Received via mailing list)
On Friday 12 February 2010 06:00:06 pm Jörg W Mittag wrote:
> Unfortunately, for this dynamic role injection stuff, we run into one
> of the (very few) limitations of Ruby. We cannot just, as Trygve says,
> "subclass the compiler"

That's true, although the suggestion that we do so made me a bit
uncomfortable. If you're right, I'll have to actually see a language 
that
implements this in order to get it, if I get it even then.

But probably the most important property Ruby has is that it's easy to
implement things that look like new syntax, but don't actually involve
touching the parser at all.

> and "add to and delete methods from the method
> dictionary" in Ruby

Sure we can! We have define_method, remove_method, undef_method,
UnboundMethod, and metaclasses. Where's the problem?

> subvert the compiler like
> James's C++ template metaprogramming implementation does.

I guess it depends how much you want to do, but we also have methods 
which can
accept blocks, which makes it very easy to create DSLs. We can also 
define
methods on classes, or even on Class itself. Whether you consider this
"subversion" is a matter of semantics, but I didn't really see anything 
in the
talk that looked impossible, except maybe the graphical representation.

> the leaky
> abstraction of ECMAScript actually *helps* rather than hurts.

I doubt it. I think what's much more useful is that ECMAScript has 
prototypal
inheritance. If you're talking about the fact that I can "steal" a 
method from
one class and apply it to another, there is only one thing stopping this 
in
Ruby, and it's some anal-retentive type-safety thing probably leftover 
from
Java or C++ -- the fact that you can't bind an UnboundMethod to anything
that's not either a direct class or a subclass of the class that 
UnboundMethod
was originally defined on.

Which just means that we can either deal purely in blocks/procs, or we 
can
define "roles" as UnboundMethods on Object.

Now, I'll grant this kind of composition is much _easier_ in ECMAScript, 
in
that we can easily rebind methods, pass them around as arguments, and 
assign
them directly to objects using the [] notation. However, just about all 
the
same tools exist in Ruby, they're just clumsier to use.
Posted by Caleb Clausen (Guest)
on 15.02.2010 10:24
(Received via mailing list)
On 2/12/10, Jörg W Mittag <JoergWMittag+Ruby@googlemail.com> wrote:
> Unfortunately, for this dynamic role injection stuff, we run into one
> of the (very few) limitations of Ruby. We cannot just, as Trygve says,
> "subclass the compiler" and "add to and delete methods from the method
> dictionary" in Ruby (although we probably *can* in Rubinius) like
> Trygve's Squeak implementation does or subvert the compiler like
> James's C++ template metaprogramming implementation does.

When people say things like this, it makes me think there ought to be
a way to do it by using RubyMacros. So, I tried to rewrite Tom/Brian's
code as macros... I think I can get rid of the need to call extend or
use method_missing/proxies. But I had to use a feature of RubyMacros
that I haven't invented yet (motivation!) and I may be missing the
point (esp as I didn't watch the movie). Since I don't know if it
would even work, I'm reluctant to post the example I came up with,,,
but if anyone really wants to see it, I will.
Posted by Thomas Sawyer (7rans)
on 15.02.2010 13:45
(Received via mailing list)
On Feb 15, 4:24 am, Caleb Clausen <vikk...@gmail.com> wrote:

> When people say things like this, it makes me think there ought to be
> a way to do it by using RubyMacros. So, I tried to rewrite Tom/Brian's
> code as macros... I think I can get rid of the need to call extend or
> use method_missing/proxies. But I had to use a feature of RubyMacros
> that I haven't invented yet (motivation!) and I may be missing the
> point (esp as I didn't watch the movie). Since I don't know if it
> would even work, I'm reluctant to post the example I came up with,,,
> but if anyone really wants to see it, I will.

Personally I think Mr. Mittag is overstating the issue. I haven't seen
anything yet to indicate that DCI is beyond implementation in regular
Ruby. But then maybe I am misunderstanding some key elements --I would
love to know. In any case, feel free to show us your code, even if it
is just an exercise in what can be done with RubyMacros.
Posted by Caleb Clausen (Guest)
on 15.02.2010 21:57
(Received via mailing list)
On 2/15/10, Intransition <transfire@gmail.com> wrote:
>
> Personally I think Mr. Mittag is overstating the issue. I haven't seen
> anything yet to indicate that DCI is beyond implementation in regular
> Ruby. But then maybe I am misunderstanding some key elements --I would
> love to know. In any case, feel free to show us your code, even if it
> is just an exercise in what can be done with RubyMacros.

Since writing that, it occurred to me that the same effect could be
achieved with regular old eval. There's always an eval equivalent to
any use of macros, but in this case the result is actually pretty
clean. So, here's my eval-based version: http://gist.github.com/304558

What I did differently: creation of the context subclass I consigned
to a utility method, since that appears to be boilerplate code. The
role class has disappeared entirely, replaced by hashes. The result is
less orthodox than the classes-and-modules approach used by brian and
yourself... but I think the minimal amount of code that users of this
context library have to write is particularly nice. I may have made
too many static assumptions, such as:

  Balance::Transfer#transfer always just calls #transfer on its child 
Roles

  Those roles in turn simply forward the #transfer message to some
other method(s)
  (increaseBalance and decreaseBalance in this case)

Please let me know what you think of this.
Posted by Brian Candler (candlerb)
on 15.02.2010 23:03
Caleb Clausen wrote:
>   Those roles in turn simply forward the #transfer message to some
> other method(s)
>   (increaseBalance and decreaseBalance in this case)
> 
> Please let me know what you think of this.

I think it's more limiting that what DCI is supposed to offer; I think 
you are supposed to inject *new* methods into the underlying objects to 
help them fulfil their roles, rather than just mapping existing ones. 
That is, the role contains extra logic which in normal OOP might pollute 
the model, and DCI helps separate it out.

I've been going through Trygve's Gantt planner example documented in 
http://heim.ifi.uio.no/~trygver/2009/bb4plan.pdf

Whilst the code appears incomplete (it relies on a base class defined 
earlier in the book), and given also that I don't grok Smalltalk, I've 
still picked up a few things. Here is one example:

Frontloader>>frontloadFrom: startWeek
   AllActivities do: [:act | act earlyStart: nil].
   [ Context reselectObjectsForRoles.
        Activity notNil
   ] whileTrue:
        [ Activity earlyStart: startWeek.
             Predecessors do:
             [ :pred |
                  (pred earlyFinish > Activity earlyStart)

In the PDF, you'll see that "AllActivities", "Context", "Activity" and 
"Predecessors" are roles, and are underlined to highlight them - a bit 
of a weakness IMO that they are not clear in the syntax.

Anyway, the Frontloader is a separate class which is (as far as I can 
see) somehow 'mixed in' to the FrontloaderCtx context object using 
roleStructure magic. But if it were a single object I think it might 
look roughly like this:

class FrontloaderCtx
  attr_reader :all_activities, :activity, :predecessors

  def initialize(model)
    @model = model
  end

  def reselect_objects_for_roles
    @all_activities = @model.all_activities
    @activity = @all_activities.find { |act|
      act.early_start.nil? && !@model.predecessors_of(act).find { |pred| 
pred.early_start.nil? }
    }
    @predecessors = @model.predecessors_for(@activity)
  end

  def frontload(start_week)
    while (reselect_objects_for_roles, activity)
      ...
    end
  end
end

which is probably not too much different to how you'd write a 
front-loader "controller", except I'd be inclined to use local variables 
for the 'roles' rather than instance variables.

However it's clear from this that the assignment of objects to roles is 
something which it intended to change during execution of a single 
method, since the whole algorithm relies on 
"reselect_objects_for_roles".

I still haven't achieved enlightenment as to what is new or different 
about "DCI". The view contexts might provide meatier examples. I did 
actually start to translate the whole lot virtually line-by-line into 
Ruby, but got a bit stuck on the UI side because I've not done any Ruby 
UI programming. It's probably possible to hook Tk in, but I don't fully 
understand what's going on in the Smalltalk yet.

Regards,

Brian.
Posted by Caleb Clausen (Guest)
on 16.02.2010 03:06
(Received via mailing list)
On 2/15/10, Brian Candler <b.candler@pobox.com> wrote:
> That is, the role contains extra logic which in normal OOP might pollute
> the model, and DCI helps separate it out.

So, you're saying that this method, which I had optimized away:

  class Balance::TransferDestination < Role
    def transfer(amount)
      increaseBalance(amount)
      puts "Tranfered to account #{__id__} $#{amount}"
    end
  end

should be able to contain arbitrary amounts of logic?

Let me think about this some more. Maybe I'll try again.

> I still haven't achieved enlightenment as to what is new or different
> about "DCI". The view contexts might provide meatier examples. I did

I have the feeling this is one of those theoretical things that seems
really complicated but once you understand it its actually quite
simple.
Posted by Brian Candler (candlerb)
on 16.02.2010 09:43
Caleb Clausen wrote:
> So, you're saying that this method, which I had optimized away:
> 
>   class Balance::TransferDestination < Role
>     def transfer(amount)
>       increaseBalance(amount)
>       puts "Tranfered to account #{__id__} $#{amount}"
>     end
>   end
> 
> should be able to contain arbitrary amounts of logic?

I think so. Otherwise you end up putting all the logic about 
*transferring* money inside the Balance object, which really should just 
be a dumb model which maintains a balance.

> I have the feeling this is one of those theoretical things that seems
> really complicated but once you understand it its actually quite
> simple.

I've not yet seen a clear (to me) exposition of what DCI actually 
*means* in practice. But then I could say the same about AOP.
Posted by James Coplien (jcoplien)
on 16.02.2010 17:41
> Then at the end, it says that an account isn't really an object at all - 
> but all the previous code has shown it as a concrete object (e.g. 
> Account.find(id)). So an example of what an account role *should* look 
> like in code would be good.

Such code has been posted in the past on object-composition, to which 
you are subscribed, Brian. You're welcome to re-post it here.

Indeed, an Account is not an object, any more than a predecessor is an 
object in the front loader example. It is a role. Remember, the D in DCI 
stands for data. In architecture, we are trying to separate many things 
from the data. MVC separates the data (the representation of 
information) from user interaction. DCI separates use case logic from 
domain logic.

The general approach to DCI is that objects should be pretty dumb. They 
are just-barely-smart data, and are usually primitive. Over the years we 
have been taught that objects should be smart and that their APIs should 
reflect what goes on in the use cases. That creates several problems. 
One problem is that rapidly changing use-case level logic is mixed in 
the same interface with slowly-changing domain interfaces. Another is 
that classes don't provide natural boundaries for the delineation of 
mental models of algorithms (as DCI used to call them when it was DCA) 
or interactions.

An account is a collection of use cases. It is in the "I" part of DCI, 
not in the "D" part. If you look at real banking software, the real 
objects are transaction logs and audit trails. They become re-configured 
in interactions on every use case, where the use cases are at the level 
of a Context object called an account. Except for its housekeeping 
references that set up the current role / instance binding at the audit 
trail and transaction level, the account is stateless. Your bank account 
is not a number sitting in memory or sitting on a disk somewhere, 
anymore than your money is sitting in a bag on a shelf in a bank 
somewhere. It is a computation: a use case. In DCI, we encapsulate those 
in Contexts.

In my talk, I catered to the usual kind of example used by consultants 
and university professors in talking about object-oriented programming, 
where they apply the little white lie of an account being an object. 
Later in the talk I introduce the concept of an account as a context. 
This is a recent and rather advanced concept in DCI.


I can see from the thread below that it was too much for the posters in 
this thread, and that the posters were unable to correlate that example 
with the description in the Artima article. The reason this is a bit 
advanced is that it comes from the design thinking that Trygve and I 
have put into DCI, rather than the nerd-level stuff. It doesn't cater to 
UML-shaped heads, or even to the way that most people characterize 
object-oriented programming. It is one of the more difficult ideas in 
DCI, and it is the one that most people trip on. Most people have so 
much trouble fitting into their mental model that they just say that it 
is wrong, or stupid. It's O.K. if you feel that way: new paradigms are 
hard, and it will take a while to unlearn old ways and to learn new.

The best way is to keep in dialog and to keep trying things out. Try to 
get above the code level and think about this from a design perspective 
(but still with the code in the back of your mind, by all means). You'll 
hopefully get to a turning point where you see programming in a totally 
different way. If you haven't gotten to that point yet, you probably 
have internalized only the nerd part of DCI. That's a good start. But as 
one poster here said: it's not about traits, it's not about injection, 
and it's not about aspects, but about something higher level. It's about 
thinking in objects while being able to separate the algorithm into 
something manageable and understandable.
Posted by James Coplien (jcoplien)
on 16.02.2010 18:06
Thomas Sawyer wrote:

> I just finished watching the 2nd video. I agree with you. Coplien does
> an awful job of explaining things. Trygve, despite his age, does a
> much better job.

Thomas, I apologize if I did not explain things well for you. To move 
things forward as a community, it's good to ask questions. I'm happy to 
try to answer. Thomas, I tell people all the time that if they fail to 
ask their business people for clarification about requirements but 
instead cast cowardly aspersions supposedly out of earshot, that it 
explains many of the problems their firms have been having in its 
developments. Maybe you behave that way with your business people, but 
I'd appreciate enough respect from you to address your concerns about 
me, to me.

>> Then at the end, it says that an account isn't really an object at all -
>> but all the previous code has shown it as a concrete object (e.g.
>> Account.find(id)). So an example of what an account role *should* look
>> like in code would be good.
> 
> I don't know what he is talking about.

Yes, it is clear that you don't understand what I am talking about.

> It's as if he thinks, if
> something isn't solid it isn't an object.

No, that isn't it. Instead of guessing, or putting words in my mouth, or 
assuming, you could have asked me. I'm pretty easy to find on the web. I 
have done my best in the above posting to answer your question. I do so 
as a service and because I think it's important that this community 
understand the subtleties here.

> And his whole speel about
> logging-in is not a usecase because there's no business goal, is silly
> too.

This represents a fundamental misunderstanding of use cases. The 
distinction between atomic operations on objects (the direct 
manipulation metaphor) and the role of algorithms (the use case angle) 
is fundamental to understanding why DCI is different from 
object-oriented programming. I use the term "use case" in the Cockburn 
sense, as a collection of possible scenarios. Each scenario is a 
collection of interactions towards a goal. I think this definition is 
consistent with Jacbosson's more formalized use case framework. I am not 
sure what you are using as your reference standard, but I would be 
interested in your arguments against Cockburn's use of the goal as a 
major element that distinguishes use cases from just blah blah blah. 
Words mean things, and use case is not just Swedish for scenario.

> He's splitting hairs over words and as much as he thinks DCI is
> so cool, I'm not sure he actually "gets it" himself.

Can you translate that into some delineated professional feedback?

> However, at the
> very beginning he does point out the main point of the whole pursuit
> -- code readability.
> 
> His Ruby code, btw, wasn't very well written, would not run and worse,
> I don't think represents DCI well either. 

Well, my version of the code runs fine here. One takes certain liberties 
with presentation in PowerPoint to a large audience to make points about 
design. And the code passes Trygve's muster as representing DCI well; we 
had been corresponding intensely to nurture the ideas using this 
example. But it is good to hear your input. Maybe we have found someone 
here in Thomas who understands DCI better than Trygve and I do. Please 
join the object-composition list, listen, learn, and contribute 
positively. When you post objections in a frustrated way on this list 
without engaging those you criticize, it makes me frustrated, and it 
does not advance our collective understanding.

If you feel the Ruby style bears improvement I am open to suggestions.

> (P.S. I also think this is much more like AOP then Coplien is willing
> to admit.)

Second, I'd like to know why; and first, I'd like to know why it's 
important. Again, I think you are making the mistake that another poster 
here warns about: confusing the language mechanisms with the design 
ideas.

These things just take time. Keep working at it, guys, and don't let 
your preconceptions get in the way... any more.
Posted by James Coplien (jcoplien)
on 16.02.2010 18:22
> I did a couple of interesting things (though I suppose I may be taking
> it too far) I thought of a Context as a Scene in a play, in which I
> defined the roles upfront (ie. at the class level) -- I use the Anise
> gem to do this, btw.  And, despite what was said in the lecture, I was
> able to use polymorphism with regard to the roles. This approach seems
> very interesting. I was able to define two methods of the same name
> that can act on the same object, but dependent on the role it plays.
> Thus the Context has a method that is dispatched to all the roles.
> While my code is from perfect the approach itself does seem like it
> could be useful for large applications. (It feels like overkill for
> small libraries though).

Right! This is the metaphor we often have been using. More precisely, 
the Context is a combination of the script (which is in the roles within 
its scope) and the casting (the dynamic mapping of roles to 
objects/actors).

I in fact have been working on a DCI pattern language based on this 
metaphor, because it works so well.
Posted by Thomas Sawyer (7rans)
on 17.02.2010 12:31
(Received via mailing list)
Hi James,

On Feb 16, 12:06 pm, James Coplien <jcopl...@gmail.com> wrote:
> explains many of the problems their firms have been having in its
> developments. Maybe you behave that way with your business people, but
> I'd appreciate enough respect from you to address your concerns about
> me, to me.

Honestly, James, I didn't even think about contacting you --I didn't
even suspect I'd be getting this deep into a conversation about it. I
was just sharing an interesting presentation, Trygve's (in which you
do a good job in the Q & A periods, btw). I looked forward to the
second video when I understood it had a Ruby example (as you might
imagine from a Ruby ethusiast). However, while your example gave me at
least something to go on, the presentation as a whole left me more
confused and thus less enthusiastic about the whole DCI idea. I
apologize for compacting this opinion into the one word "awful", I
suppose that is too disparaging a term, and for that I apologize. So
please accept this explanation in it's place and take it for what it's
worth.

> > something isn't solid it isn't an object.
>
> No, that isn't it. Instead of guessing, or putting words in my mouth, or
> assuming, you could have asked me.

 No, no. I wasn't putting words in your mouth. I was expressing what
*I* was getting out of your words.

> distinction between atomic operations on objects (the direct
> manipulation metaphor) and the role of algorithms (the use case angle)
> is fundamental to understanding why DCI is different from
> object-oriented programming. I use the term "use case" in the Cockburn
> sense, as a collection of possible scenarios. Each scenario is a
> collection of interactions towards a goal. I think this definition is
> consistent with Jacbosson's more formalized use case framework. I am not
> sure what you are using as your reference standard, but I would be
> interested in your arguments against Cockburn's use of the goal as a
> major element that distinguishes use cases from just blah blah blah.
> Words mean things, and use case is not just Swedish for scenario.

The definition seems fine. I just don't see why logging-in can't be
viewed as a goal in itself.

> > He's splitting hairs over words and as much as he thinks DCI is
> > so cool, I'm not sure he actually "gets it" himself.
>
> Can you translate that into some delineated professional feedback?

Ok. This is my take. DCI seems to me like an idea with a lot of
potential. But I don't think it's an all of nothing kind of thing. I
get the feeling that you so badly want DCI to be a Major Paradigm
Shift that you might be pushing it's concepts too far.

For instance, to say that an account is not a not object... going all
the way back to the bad old days of COBOL, an account has always been
treated as as object, even if not coded in OOP form. That's because
banks treat accounts as objects --people have them, they have ID
numbers, etc. Writing a banking system without the concept of an
account ignores the very system to be modeled. I'm pretty sure that
any attempt to do so will prove far less readable (exactly the
opposite of what DCI is trying to achieve) then any program that does
--even in COBOL. Moreover, when you say an account isn't an object and
yet give a presentation where it is an object, that's just confusing.

> > However, at the
> > very beginning he does point out the main point of the whole pursuit
> > -- code readability.
>
> > His Ruby code, btw, wasn't very well written, would not run and worse,
> > I don't think represents DCI well either.
>
> Well, my version of the code runs fine here.

Then please make it available!

> One takes certain liberties
> with presentation in PowerPoint to a large audience to make points about
> design. And the code passes Trygve's muster as representing DCI well; we
> had been corresponding intensely to nurture the ideas using this
> example. But it is good to hear your input. Maybe we have found someone
> here in Thomas who understands DCI better than Trygve and I do. Please
> join the object-composition list, listen, learn, and contribute
> positively. When you post objections in a frustrated way on this list
> without engaging those you criticize, it makes me frustrated, and it
> does not advance our collective understanding.

Please don't feel that I am criticizing *you* --take it for what it
is, my personal critique of *your presentation*.

> If you feel the Ruby style bears improvement I am open to suggestions.

I can can certainly offer some suggestions, but I would have to
understand DCI better to go beyond the surface. I posted my take on
it, but being new to DCI, I can only guess if I am on the right track
or not.

> > (P.S. I also think this is much more like AOP then Coplien is willing
> > to admit.)
>
> Second, I'd like to know why; and first, I'd like to know why it's
> important. Again, I think you are making the mistake that another poster
> here warns about: confusing the language mechanisms with the design
> ideas.

The goal of AOP is to come at a problem orthogonal to the traditional
OOP direction. In AOP you are organizing code into aspects. These
aspects are like contexts in DCI. Aspects are composed of advice, code
injected into classes/objects by wrapping other methods.
There are clear similarities. DCI goes a bit further by injecting
methods whole-clothe, and in doing so decomposes "aspects" into a
context and set of roles. (Actually that might be useful, might DCI
roles make use of AOP's concept of advice too?)
Posted by Thomas Sawyer (7rans)
on 17.02.2010 12:39
(Received via mailing list)
On Feb 16, 11:41 am, James Coplien <jcopl...@gmail.com> wrote:

> hard, and it will take a while to unlearn old ways and to learn new.
No matter how hard anew paradigms is, it must still be taught.
Posted by Thomas Sawyer (7rans)
on 17.02.2010 12:44
(Received via mailing list)
On Feb 17, 6:31 am, Intransition <transf...@gmail.com> wrote:

> The goal of AOP is to come at a problem orthogonal to the traditional
> OOP direction. In AOP you are organizing code into aspects. These

"goal" isn't the right word actually, more like "tactic".
Posted by Michel Demazure (badal)
on 17.02.2010 14:48
Thomas Sawyer wrote:

> No matter how hard a new paradigms is, it must still be taught.

Dear All,

Indeed !

Please do not end this very interesting discussion. Some people may be 
eagerly following it without participating (at least I am).
Posted by Michal Suchanek (Guest)
on 17.02.2010 16:49
(Received via mailing list)
On 13 February 2010 19:07, David Masover <ninja@slaphack.com> wrote:

>
> I doubt it. I think what's much more useful is that ECMAScript has prototypal
> inheritance. If you're talking about the fact that I can "steal" a method from
> one class and apply it to another, there is only one thing stopping this in
> Ruby, and it's some anal-retentive type-safety thing probably leftover from
> Java or C++ -- the fact that you can't bind an UnboundMethod to anything
> that's not either a direct class or a subclass of the class that UnboundMethod
> was originally defined on.
>

Obviously, if you unbind a method from Array which is implemented in C
you cannot rebind it to something else. This restrictions is probably
less meaningful for pure ruby methods but allowing some methods to be
rebound freely and restrict others does not sound very nice either.

Thanks

Michal
Posted by Brian Candler (candlerb)
on 17.02.2010 17:10
> Please do not end this very interesting discussion. Some people may be 
> eagerly following it without participating (at least I am).

I've been taking apart one of the Smalltalk examples in an attempt to 
understand it and perhaps port bits of it to Ruby. Trygve himself has 
been gracious in helping me through this process. You can follow the 
discussion here:

http://groups.google.com/group/object-composition/browse_thread/thread/854df3a328e1c263
Posted by James Coplien (jcoplien)
on 17.02.2010 17:47
Thomas Sawyer wrote:
> On Feb 16, 11:41�am, James Coplien <jcopl...@gmail.com> wrote:
> 
>> hard, and it will take a while to unlearn old ways and to learn new.
> No matter how hard anew paradigms is, it must still be taught.


No. I was a professional educator for several years. One thing you find 
in the theories of education is that though many things can be learned, 
only some of them can be taught — in the normal Western application of 
the word "teaching."

The normal model of education, as described by educators like Piaget, is 
to move from the known to the unknown. The essence of a paradigm shift, 
according to Kuhn, is that the new paradigm is irreconcilable with the 
old. I think that's what we're faced with here. As such, I think the 
best way to learn is through practice.

Furthermore, I think it is better to think of DCI as a community effort 
to explore a new space, working with each other, than to have the Master 
"instruct" the newbies. It is true that Trygve and I have about ten 
years of thought about this, and we're happy to relate our experiences. 
That's why I'm here — to give. That's why Trygve has published so many 
reports and why we published a joint report on Artima. That's why I have 
spent the past three years writing a book on this (and related) topics. 
Learning this will take hard work: don't expect to be spoon-fed.
Posted by Michel Demazure (badal)
on 17.02.2010 17:50
Brian Candler wrote:
 You can follow the
> discussion here:
> 
> http://groups.google.com/group/object-composition/browse_thread/thread/854df3a328e1c263

We'll keep both eyes open !
Posted by James Coplien (jcoplien)
on 17.02.2010 18:33
Thomas Sawyer wrote:

> Hi James,
> 
> Honestly, James, I didn't even think about contacting you --I didn't
> even suspect I'd be getting this deep into a conversation about it.

The I'm happy to offer a revelation in your mindset. And welcome to the 
Internet world.


> However, while your example gave me at
> least something to go on, the presentation as a whole left me more
> confused and thus less enthusiastic about the whole DCI idea.

That is in fact probably good! That is what should be happening as you 
make a paradigm shift. Expect to be confused and surprised.

I'll come back to this notion throughout the mail.

My example didn't only extemporize on Trygve's, but went into some new 
territory. And I think some people got lost there.

I know this sounds like rationalization, but in fact, most of my 
teaching the past thirty years has involved some kind of paradigm shift, 
and I am attentive to the need of this puzzlement. If you read "Zen and 
the art of motorcycle maintenance," Pirsig calls it "stuckness." 
Learning new things is not always a linear process.


> I apologize for compacting this opinion into the one word "awful", I
> suppose that is too disparaging a term, and for that I apologize. So
> please accept this explanation in it's place and take it for what it's
> worth.

You can call me whatever you want to my face, and in this discussion, I 
hope you do, you ignoramous :-) I am more hurt by the fact that you 
might have seized an opportunity for dialog and learning but instead 
cast aspersions mumbling in a corner somewhere. I feel hurt on behalf of 
the community. We need your criticism — but in dialog.


>> Words mean things, and use case is not just Swedish for scenario.
> 
> The definition seems fine. I just don't see why logging-in can't be
> viewed as a goal in itself.

As most use case experts would describe it, you don't go home at the end 
of the day and tell your daughter, "Guess what I did today! I got logged 
in!" Logging in isn't essential to the value chain. The goals in 
goal-driven use cases drive towards such goals. To focus on things at 
this level is noise.

Alistair Cockburn's "Effective Use Cases" offers the theory and practice 
of this perspective in a very satisfying way. Give it a read and come 
back and we can discuss it more.


>> > He's splitting hairs over words and as much as he thinks DCI is
>> > so cool, I'm not sure he actually "gets it" himself.
>>
>> Can you translate that into some delineated professional feedback?
> 
> Ok. This is my take. DCI seems to me like an idea with a lot of
> potential. But I don't think it's an all of nothing kind of thing.

No one is saying that it is! There is still a place for your 
grandfather's object-oriented programming. There are architectures we 
can call event-driven architectures, where the interesting operations 
are all atomic. A shapes editor is a good example. It in fact has no use 
cases. Most operations are atomic and trivial: "Change the color of this 
shape." "Resize this shape." "Create this shape." Once in a great while 
you might have operations involving multiple methods of multiple shapes, 
and that's where DCI comes in.

More broadly, not everything is object-oriented, whether DCI or your 
grandfather's object-oriented design. Procedural design still has a 
place. So do state machines — and that has nothing to do with objects 
(for example, in protocol design). So does rule-based computation. So 
does functional programming as in SASL or KRC. Anyone who attacks the 
world with one weapon alone will be defeated. I wrote a whole book on 
this several years ago called "Multi-paradigm design.

Why did you think I felt that DCI was the only way?


> get the feeling that you so badly want DCI to be a Major Paradigm
> Shift that you might be pushing it's concepts too far.

Given that it took me seven years to learn it, I can speak strongly for 
the fact that it is a paradigm shift. That it is a paradigm shift has 
nothing to do with its payoff — only with the mode of understanding.

You may be seeing some of my pedagogical techniques that are commonly 
used to extemporize new ideas. There are important ways of giving 
emphasis in a one-hour presentation that would not arise if we were 
pairing at a keyboard.


> For instance, to say that an account is not a not object... going all
> the way back to the bad old days of COBOL, an account has always been
> treated as as object, even if not coded in OOP form.

I don't think so. Have you ever worked in finance or banking? I think 
your statement holds true only in lectures by college professors or by 
people outside of finance. In the latter case, the object isn't the 
account, but the name of the account (sometimes called its account 
number). Can you give me a single example in the software of a real 
financial institution where the balance is actually stored as a data 
member of an object in memory?

After you answer that, we can discuss the difference between 
object-oriented programming and class-oriented programming. One of the 
major features of DCI is that it supports object-oriented programming. 
Very few languages support object-oriented programming directly: they 
support class-oriented programming instead.


> That's because
> banks treat accounts as objects --people have them, they have ID
> numbers, etc.

You are perhaps suffering from being trapped in the old paradigm, where 
everything must be an object. Stick with me here for a few paragraphs as 
I explore this. You would have been an excellent student of Kant. In 
fact, if you look at people's mental models of their worlds, they think 
of much more than objects. An ID number is not an object: it is a handle 
to an object. An account is not an object: it is a role that several 
objects together can play.

Do the following experiment. Go to someone who has recently done a money 
transfer in their bank. Ask them to give you a general user story for 
it. Inevitably, I find people saying, "I decide on an amount, and then I 
witdraw that money from one account and put it into another account." If 
they speak more precisely they will use terms like "source account" and 
"destination account." A "source account" is not an object. It is a role 
that something can play (like a savings account).

For the time being we can pretend that savings account is a class whose 
objects can play the role of "source account." That fits the simple 
Kantian model of the world, where most things must be objects. But if we 
go more deeply, to the level of that domain (in the sense of DDD) we 
find that it is not an object — certainly not in the "D" sense of "Data" 
in DCI. It is a collection of use cases, of behaviors. That makes it a 
DCI context. An account is a context (like an account number) in which 
we can carry out algorithms (like transferring money) with other 
concepts (like other accounts, or transaction logs, or audit trails).

Where I think you are confused is that you take these elements of your 
mental model and call them objects. That was also what Kant does. To do 
so is at least not useful, and probably isn't even right. Also part of 
your mental model is the mapping from the roles "source account" and 
"destination account" onto their respective accounts (my savings account 
#O991540 and my investment account #393497654). Also part of your mental 
model is those things called accounts, and you think of them as objects. 
The problem is that the people who implement those systems don't 
implement them as objects, but as something else — the objects are at a 
much lower level. That's the real world of real financial software 
today. Really. At least in my example — which I think is representative. 
If you have a different example where an account can be an object in 
memory, I find that interesting, but I don't think it's germane to this 
discussion.

One reason I can justify DCI as a paradigm shift is that it differently 
translates the mental models of end users and programmers into code. 
Something called object-oriented programming was one way of doing it in 
the 1980s. This is another way of doing it, with different elements of 
the model. And these elements don't come out of thin air. Rebecca 
Wirfs-Brock and Trygve were having a discussion on the Hurtigruten about 
ten years ago as I was listening, and they concluded that objects don't 
have responsibilities — roles do. That is the essence of CRC cards. Most 
people think that CRC stands for "Class, Responsibility, and 
Collaborator." It does not. Rebecca wanted to call them RRR cards 
(Roles, Responsibilities and Relationships) but the C really stuck. What 
it really means is "candidate object," and it's a role. (I just verified 
this with her when she and I went together to dinner with Trygve and 
Gertrud at Øredev last year.) So you have an entire industry focusing on 
classes because they misunderstood an acronym (or popularizers of the 
technique misunderstood it – I won't mention any names). Focus on roles 
— the roles that objects can play — not classes.

There are other ideas I could bring to bear from the field of user 
experience, from Brenda Laurel's writings, and from other staples of 
object-orientation that the Java-duped public doesn't read, but take my 
word for it. This is not the object-orientation you learned in college.



> Then please make it available!

It's there (somewhere) on object-composition (are you subscribed?); it 
appears in its entirety in the book I have coming out in June (there are 
several drafts scattered here and there on the web).

Part of understanding a new paradigm is going beyond a one-hour talk to 
do your homework. Read the Artima article. There are three or four 
articles you should probably read at Trygve's web site. If you're really 
interested, come to the next course I offer on it. Just for you, I'll 
give you a free seat.


> Please don't feel that I am criticizing *you* --take it for what it
> is, my personal critique of *your presentation*.

Likewise, I am not criticising your understanding, but how you channeled 
the criticism.


>> If you feel the Ruby style bears improvement I am open to suggestions.
> 
> I can can certainly offer some suggestions, but I would have to
> understand DCI better to go beyond the surface.

I suspected as much. My guess is that your sense of distaste in the code 
may also owe to being stuck in the old paradigm.


>> > (P.S. I also think this is much more like AOP then Coplien is willing
>> > to admit.)
>>
>> Second, I'd like to know why; and first, I'd like to know why it's
>> important. Again, I think you are making the mistake that another poster
>> here warns about: confusing the language mechanisms with the design
>> ideas.
> 
> The goal of AOP is to come at a problem orthogonal to the traditional
> OOP direction. In AOP you are organizing code into aspects. These
> aspects are like contexts in DCI. Aspects are composed of advice, code
> injected into classes/objects by wrapping other methods.
> There are clear similarities. DCI goes a bit further by injecting
> methods whole-clothe, and in doing so decomposes "aspects" into a
> context and set of roles. (Actually that might be useful, might DCI
> roles make use of AOP's concept of advice too?)

No, because it makes the aspectualized code unreadable. As to why DCI is 
more than AOP, read my above long segment on mental models and 
paradigms. DCI is not just a programming trick to reflect cross-cutting. 
It can represent much higher dimensions of cross-cutting than AOP can 
and, because of the Contextual mapping of roles to objects, is much more 
dynamic. They are barely in the same league. I think you are confusing 
one of the mechanisms of Aspects with one common mechanism used to 
implement DCI in some programming languages.

This, too, is the sign of a new paradigm: everyone tries to describe it 
in terms of what they know. Some people say that DCI is like mixins. 
Some say it is like multi-paradigm design. Some say it is like aspects, 
some like dependency injection, and a million other things. What gives 
me the most grief is that there is a tiny bit of truth in each of these 
claims, just enough to keep people from making the necessary mental 
leap. To do that requires digging into it and trying it. It is like 
learning a martial art: no number of PowerPoint slides will get you 
there. You have to feel it in your bones. Most people don't even "get" 
object-oriented programming in their bones. And this transition scares 
programmers because their identity is so tied up in understanding new 
technology. That leads people to do really amusing things. For example, 
someone may not yet understand DCI well enough even to give suggestions 
on how to clean up Ruby code that illustrates it, yet feels qualified to 
criticize one of its inventors as "not getting it." O, how human we can 
be...

But back to the point... The real goal of AOP (I have this from Gregor 
Kiczales personally) is to shock people into taking reflection 
seriously. It was supposed to scare people from Java back into Lisp, 
where you can express these things cleanly. Cutpoints and wrappers and 
whoppers are native to CLOS, for example. The problem is that people 
weren't shocked: they embraced the scaffolding. I view this as one of 
the best examples of the sheep-like stupidity of the industry, 
collectively.

I'm going to get back to my vacation and attacking the fjelds of Norway.

Med venlig Hilsen, Cope
Posted by Marnen Laibow-Koser (marnen)
on 17.02.2010 20:53
James Coplien wrote:
[...]
>> For instance, to say that an account is not a not object... going all
>> the way back to the bad old days of COBOL, an account has always been
>> treated as as object, even if not coded in OOP form.
> 
> I don't think so. Have you ever worked in finance or banking? I think 
> your statement holds true only in lectures by college professors or by 
> people outside of finance. In the latter case, the object isn't the 
> account, but the name of the account (sometimes called its account 
> number). Can you give me a single example in the software of a real 
> financial institution where the balance is actually stored as a data 
> member of an object in memory?

I have yet to watch your presentation (though I am very much looking 
forward to doing so), and I know that you and Trygve generally know what 
you're talking about.  So I may be a fool rushing in where angels fear 
to tread.  But...

I cannot imagine *not* representing a bank account as an object in a 
bank software system.  The balance is part of such an object's state.

> 
> After you answer that, we can discuss the difference between 
> object-oriented programming and class-oriented programming. One of the 
> major features of DCI is that it supports object-oriented programming. 
> Very few languages support object-oriented programming directly: they 
> support class-oriented programming instead.

Often quite true.

> 
> 
>> That's because
>> banks treat accounts as objects --people have them, they have ID
>> numbers, etc.
> 
> You are perhaps suffering from being trapped in the old paradigm, where 
> everything must be an object. Stick with me here for a few paragraphs as 
> I explore this. You would have been an excellent student of Kant. In 
> fact, if you look at people's mental models of their worlds, they think 
> of much more than objects. An ID number is not an object: it is a handle 
> to an object.

Agreed.

> An account is not an object: it is a role that several 
> objects together can play.

Not necessarily agreed.  In the example below, you're talking about 
accounts as objects while claiming you're not doing so.

> 
> Do the following experiment. Go to someone who has recently done a money 
> transfer in their bank. Ask them to give you a general user story for 
> it. Inevitably, I find people saying, "I decide on an amount, and then I 
> witdraw that money from one account and put it into another account." If 
> they speak more precisely they will use terms like "source account" and 
> "destination account." A "source account" is not an object. It is a role 
> that something can play (like a savings account).

I believe that you're getting trapped by ambiguous language here.  A 
"source account" is not an object, to be sure, but that doesn't mean an 
*account* isn't an object.  "Source account" and "destination account" 
are roles, but only accounts (or objects that behave like accounts) can 
play those roles, it seems to me.

In Ruby:

def transfer(source, destination, amount)
  ...
end

peter = Account.find(:peter)
paul = Account.find(:paul)

Now we have handles to Peter's account and Paul's account.  Of course we 
don't have the accounts themselves, but we have object representations 
of them.

Now we can do
transfer(peter, paul, 100)
in which case peter plays the role of source account
or we can do
transfer(paul, peter, 100) in which case paul plays the role of source 
account.  Where's the problem here?


> 
> For the time being we can pretend that savings account is a class whose 
> objects can play the role of "source account." That fits the simple 
> Kantian model of the world, where most things must be objects. But if we 
> go more deeply, to the level of that domain (in the sense of DDD) we 
> find that it is not an object — certainly not in the "D" sense of "Data" 
> in DCI. It is a collection of use cases, of behaviors. 

The point of a "traditional" object, it seems to me, is that it unifies 
data and behavior in one package.  DCI may be a valid form of analysis, 
orthogonal to "traditional" object analysis, but that doesn't mean that 
objects revealed by traditional object analysis (such as the Account 
instances in your example) aren't objects.

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
marnen@marnen.org
Posted by James Coplien (jcoplien)
on 17.02.2010 23:01
Marnen Laibow-Koser wrote:
> James Coplien wrote:
> [...]

> I cannot imagine *not* representing a bank account as an object in a 
> bank software system.  The balance is part of such an object's state.

No. In every example I've seen, financial records are kept as audit 
trails that track deposits, withdrawals, interest accruals, etc. There 
is no "balance" sitting on a disk nor sitting in memory. The balance is 
computed as the sum of accruals, less the sum of decreases, against some 
baseline. All these data are in a database — but no balance.

Let me reiterate my question, which yet goes unanswered here: Can you 
name me one, real, concrete system in real use, in a real financial 
institution, where the account is an object, and its field is a balance, 
within a system that manages the account itself?


> Not necessarily agreed.  In the example below, you're talking about 
> accounts as objects while claiming you're not doing so.

I start talking about them as objects as a way to introduce the concept. 
Then I move to the real design to introduce how Contexts can replace 
objects in some contexts.



> I believe that you're getting trapped by ambiguous language here.  A 
> "source account" is not an object, to be sure, but that doesn't mean an 
> *account* isn't an object.  "Source account" and "destination account" 
> are roles, but only accounts (or objects that behave like accounts) can 
> play those roles, it seems to me.


I agree that this is an issue of misunderstanding. Your code example has 
nothing to do with the point I'm making. Think of the point I'm making 
as having to do with the psychology of perception (which is what Dahl 
and Nygård viewed OO as being all about in the end). In your example, 
peter is a name for an identifier which contains a reference (an 
address, another kind of name) of something called an account. That it 
can be an object in Ruby doesn't mean that it properly reflects the 
proper mental model. For example, I can also do this in Ruby:

   def account (account_id, amount)
       . . . .
   end

So what? And I have the same "so what" reaction to your code.

I agree with your above analysis that accounts, or objects that behave 
like accounts, can play these roles. Can my phone bill play the role of 
an acccount? If it does, is it an account in the banking sense? Of 
course not. But I can transfer money to it — because it can play the 
role of a source account. So it *can* be a data object. My point is that 
it doesn't have to be, and that in fact, very few accounts are. They 
rather are Contexts than Data objects.

This facet of the underpinnings of DCI is not about language expression, 
but of about how we think. That's the paradigm shift part.
Posted by Marnen Laibow-Koser (marnen)
on 18.02.2010 00:08
Thanks for replying!  I've probably injected myself into a debate that's 
a bit over my head, but that's how learning happens.

James Coplien wrote:
> Marnen Laibow-Koser wrote:
>> James Coplien wrote:
>> [...]
> 
>> I cannot imagine *not* representing a bank account as an object in a 
>> bank software system.  The balance is part of such an object's state.
> 
> No. In every example I've seen, financial records are kept as audit 
> trails that track deposits, withdrawals, interest accruals, etc. There 
> is no "balance" sitting on a disk nor sitting in memory. The balance is 
> computed as the sum of accruals, less the sum of decreases, against some 
> baseline. All these data are in a database — but no balance.

That's implementation.  It is irrelevant to interface, no?

> 
> Let me reiterate my question, which yet goes unanswered here: Can you 
> name me one, real, concrete system in real use, in a real financial 
> institution, where the account is an object, and its field is a balance, 
> within a system that manages the account itself?

First, your question probably goes unanswered because the only people 
who could answer it are people who've worked on the proprietary systems 
in question.  I have the impression that not much financial software is 
open source.

Second, it's irrelevant whether balance is a field or a calculation, at 
least if the uniform access principle is still to hold.  As a 
hypothetical user of class Account, I want to be able to call 
Account#balance and get a balance.  I don't care in the least what has 
to go on to get me that balance.

> 
> 
>> Not necessarily agreed.  In the example below, you're talking about 
>> accounts as objects while claiming you're not doing so.
> 
> I start talking about them as objects as a way to introduce the concept. 
> Then I move to the real design to introduce how Contexts can replace 
> objects in some contexts.

OK.

> 
> 
> 
>> I believe that you're getting trapped by ambiguous language here.  A 
>> "source account" is not an object, to be sure, but that doesn't mean an 
>> *account* isn't an object.  "Source account" and "destination account" 
>> are roles, but only accounts (or objects that behave like accounts) can 
>> play those roles, it seems to me.
> 
> 
> I agree that this is an issue of misunderstanding. Your code example has 
> nothing to do with the point I'm making. Think of the point I'm making 
> as having to do with the psychology of perception (which is what Dahl 
> and Nygård viewed OO as being all about in the end). In your example, 
> peter is a name for an identifier which contains a reference (an 
> address, another kind of name) of something called an account. 

So far so good.

> That it 
> can be an object in Ruby doesn't mean that it properly reflects the 
> proper mental model. 

I think of an account as being an object. Doesn't that make it the 
proper mental model for me?

> For example, I can also do this in Ruby:
> 
>    def account (account_id, amount)
>        . . . .
>    end
> 
> So what? 

I don't get your point here at all.  Please elaborate.

> And I have the same "so what" reaction to your code.
> 

Why?

> I agree with your above analysis that accounts, or objects that behave 
> like accounts, can play these roles. Can my phone bill play the role of 
> an acccount? If it does, is it an account in the banking sense? Of 
> course not. But I can transfer money to it — because it can play the 
> role of a source account. So it *can* be a data object.

Uh, what?  You can't transfer money to your phone bill.  You can 
transfer money to your account at the phone company -- and you can do so 
precisely because it is (or behaves like) an account.

> My point is that 
> it doesn't have to be, and that in fact, very few accounts are. They 
> rather are Contexts than Data objects.

And I really don't see where you come to that conclusion.

> 
> This facet of the underpinnings of DCI is not about language expression, 
> but of about how we think. That's the paradigm shift part.

Yes, but I so far do not agree with your premises here, which means I 
can't agree with the paradigm that develops from them.  I'm certainly 
willing to be convinced, though.

Best,
--
Marnen Laibow-Koser
marnen@marnen.org
http://www.marnen.org
Posted by James Coplien (jcoplien)
on 19.02.2010 18:20
Let me respond to bits of Marnen's excellent post at a time.

Marnen Laibow-Koser wrote:
> Thanks for replying!  I've probably injected myself into a debate that's 
> a bit over my head, but that's how learning happens.

For all of us


> James Coplien wrote:
>> Marnen Laibow-Koser wrote:
>>> James Coplien wrote:
>>> [...]
>> 
>>> I cannot imagine *not* representing a bank account as an object in a 
>>> bank software system.  The balance is part of such an object's state.
>> 
>> No. In every example I've seen, financial records are kept as audit 
>> trails that track deposits, withdrawals, interest accruals, etc. There 
>> is no "balance" sitting on a disk nor sitting in memory. The balance is 
>> computed as the sum of accruals, less the sum of decreases, against some 
>> baseline. All these data are in a database — but no balance.
> 
> That's implementation.  It is irrelevant to interface, no?

It affects the internal form of the system. That form is called its 
architecture: the parts and their relationships. Those parts have 
interfaces, and the way we think about them affects the way they are 
implemented in the code.

For example, if we implement a bank system in terms of incremental audit 
trails and dynamic association between those elements and roles that 
appear in dynamically created account Contexts, it's a much different 
design than if an Account is a data object. It shows through. Kent Beck 
has long argued that you can't hide a bad design behind a good 
interface. Brenda Laurel emphasizes the importance of the direct 
manipulation metaphor. Alan Kay talks about these objects as extensions 
of the images of your own mind. That is what DCI is trying to do.

More to the point, the way that the market thinks about them (the 
stakeholders) affects their rates of change. Much of design is about 
eliciting change points so that frequently changing stuff is easy to 
change, is localized, and is separated from the stuff that doesn't 
change so much. That isn't all in the interface, unfortunately. In fact, 
it is often just the opposite. Most of the interface of a Prius car is 
the same as that for an ordinary gasoline-powered automobile, but the 
internal architecture is radically different.


>> Let me reiterate my question, which yet goes unanswered here: Can you 
>> name me one, real, concrete system in real use, in a real financial 
>> institution, where the account is an object, and its field is a balance, 
>> within a system that manages the account itself?
> 
> First, your question probably goes unanswered because the only people 
> who could answer it are people who've worked on the proprietary systems 
> in question.  I have the impression that not much financial software is 
> open source.

O.K., well, I can speak for what I have seen in Saxo Bank, in Swiss Bank 
Chicago, in Swiss Bank London, in Allianz, in a large Danish pension 
company and in many other discussions with financial people at 
conferences. Even Ron Jeffries' XP book features a user story that 
describes an account balance in these terms. If you have done your 
domain analysis, these things are obvious to someone in the business.

Another obvious failure is that people designing a telecom system 
thinking that a phone call is an object. It isn't an object in any phone 
system I've seen. I've seen many inside AT&T and Western Electric, and 
publications from Bell Northern Research / Nortel indicate that also 
avoid this failure mode. The same was true at Avaya, AGCS, ... shall I 
go on?

The problem is that objects became really popular in the industry in 
about 1990 and now everything that is a Thing has to be an object. The 
naivté was fueled by early methodologists who told us a number of silly 
things: everything is an object; objects should be created in isolation; 
objects are the nouns in your requirements document; and so forth.

And so we have a claim here about accounts being objects, 
unsubstantiated in reality, but based in such an overwhelmingly strong 
mythology that it prompts multiple denials about the claim of how real 
systems implement this. It is a matter of maturity. It is easy to 
stumble into a great tool like Ruby and to look for ways to apply its 
class facilities to everything in site. But there are much more subtle 
structures at work here. What's really cool about Ruby is that rises 
even to this challenge. (Most languages can express DCI concepts in some 
degree. There's only one popular language that can't, and I'll let you 
figure that out. Class, that's your homework assignment for tomorrow.)

The popular, naive claim doesn't work in practice — which is why you 
don't see it in practice. Let's contemplate your account example with a 
balance as a member. What is the object's scope? Its lifetime? How many 
of these objects exist in a banking system? How is concurrency handled 
(that's the killer): when the actuaries and account holder and the bank 
want to access it at the same time? What is the scope and duration of a 
transaction in terms of the object? If you have transaction semantics 
(and all banks do, to avoid losing money under concurrency) what is the 
mapping from the object model to the transactional model and the 
relational model that usually supports it? Remember: Ontos and its 
cousins were largely failures, because they tried to stay in the 
paradigm of your grandfather's object-oriented architecture. The 
complexity just got out of hand.

DCI actually offers reasonable answers to all of these questions, 
because it's rooted in structures that can capture and express higher 
levels of complexity, both static and dynamic, than a POJO approach can. 
I think that's what got this thread started: I described a solution to a 
problem that is more complex than people can conceptualize using their 
grandfather's object-oriented programming, and understanding broke down. 
I think that people fail to understand it's a paradigm shift — but 
that's maybe a liability of taking one's understanding from a few hours 
of videotapes.


> Second, it's irrelevant whether balance is a field or a calculation, at 
> least if the uniform access principle is still to hold.


That claim holds only within a single contextual thread. Another set of 
immature foundations can be found in the Agile world where we are 
supposed to be focused on the customer. And most of the naive claims 
about accounts here come from that perspective. I can just read the user 
stories and use those to drive my design, using TDD or something else. 
Just find all the elements of all the interfaces and just organize them.

The fact is that most of the computation in a bank has nothing to do 
with someone who has an account, but who is in the back office managing 
investments or doing analyses. They're called actuaries in English. 
Actuaries care little about the status of your bank account. They care 
about the transactions.

There are many other sets of users who are looking at these data: 
auditors, tellers, ATM machines, other banks, the national bank, 
investors, loan officers, bank executives. All you need to do is to take 
all the responsibilities of all those stakeholders and divide them up 
into nice interfaces that give you nice objects that have nice coupling 
and cohesion. It's intractably complex.

DDD has recently drawn attention to the importance of unearthing domain 
concepts that are stable over time. They have little to do with the 
requirements of the stakeholders. Very few people understand that. The 
"dumb" data objects of DCI come from this domain analysis; they are 
often the model objects one finds in MVC. The intelligence that serves 
the actuaries, the accountants, the loan officers and everyone else play 
out in use cases that are defined in terms of roles — roles that are 
mapped onto the right domain objects at the right time by the right 
context.

The essence of an object-oriented system is that the mappings from roles 
to objects changes thousands or millions of times a second. Your 
grandfather's OO simulated a very weak version of that called inclusion 
polymorphism. The DCI mapping brings these dynamics to the surface.

> As a 
> hypothetical user of class Account, I want to be able to call 
> Account#balance and get a balance.  I don't care in the least what has 
> to go on to get me that balance.

So you don't care about its data. It is essentially a service, a 
computation. We collect those services together in DCI and call them 
Contexts. You instead are trying to convince me that they should be 
objects. O.K., a Context is an object by some definition, and if that's 
enough for us to agree, then we agree. But it is not a domain object — 
that creates an architecture where the pressure points of change are all 
in the wrong place. A simple domain analysis of a financial application 
will bear that out quickly.

More to the point, it is useful to distinguish between objects (as Dahl 
or Nygaard would recognize them) and the roles that they play. If 
programming language is to be about intentionality (communicating the 
design intent of the programmer) then we want the programming formalisms 
to carry this distinction forward. That's what DCI is: a set of 
formalisms that carry archetypical elements of human cognition and 
machine computation forward into the code.

Calling it an object is a little like calling it a thing. I want a 
little more insight from these labels.


> I think of an account as being an object. Doesn't that make it the 
> proper mental model for me?

No, you're a programmer. And that's O.K.: programmers are people, too, 
and we need to support ehir model. But, again, object orientation is all 
about capturing mental models in code, and we need to be attentive to 
stakeholders other than the programmer. Like Raskin said: The interface 
is the program. A user experience person would pursue this issue using 
the kind of question I posed in an earlier post, leading to the 
description (e.g., for a money transfer) that I think about things in 
terms of source accounts and destination accounts. Unfortunately, my 
bank doesn't have source accounts. I can conceptualize a source account, 
but can't create one, can't open one, can't find one. They're not
*objects*. They're protocols, or interfaces to objects. They're roles. 
Those, too, are part of our mental models. And they should be part of 
the code as well. If you look at where Rebecca Wirfs-Brock has taken 
responsibility-driven design, it is into this realm of roles. Objects 
don't have responsibilities; their roles do. That was the conversation 
that Trygve and I recall from his discussion with Rebecca on the deck of 
the Hurtigruten all those years ago. There are some additional concepts 
that we should be attentive to as well, including algorithms and the 
associations from roles to objects. DCI packages most of these in roles 
and Contexts.

If all you have learned is objects, then everything to you is an object. 
That is whey I said you might make a good student of Kant. A good 
exploration of end-user mental models shows that they are much more 
subtle. Introducing roles provides a much better match for this model 
and provides a much better foundation for good software structure than 
the pure object approach does. Trygve published some preliminary metrics 
about this on object-composition, and you might have a look at them and 
at the surrounding discussion.


> Uh, what?  You can't transfer money to your phone bill.  You can 
> transfer money to your account at the phone company -- and you can do so 
> precisely because it is (or behaves like) an account.

No, the entity I manipulate on my web page is exactly my phone bill. 
(Denmark has an advanced banking system, so maybe those of you in other 
countries still do this with checks to the phone company and so forth — 
but even for one of my accounts outside Europe, I can treat the phone 
bill as an entity.) That's my mental model. It's not that I'm paying the 
phone company; I pay my phone bill. No one says at the end of the month 
"I need to pay my phone company." They say "I need to pay my phone 
bill."


>> My point is that 
>> it doesn't have to be, and that in fact, very few accounts are. They 
>> rather are Contexts than Data objects.
> 
> And I really don't see where you come to that conclusion.
> 
>> 
>> This facet of the underpinnings of DCI is not about language expression, 
>> but of about how we think. That's the paradigm shift part.
> 
> Yes, but I so far do not agree with your premises here, which means I 
> can't agree with the paradigm that develops from them.  I'm certainly 
> willing to be convinced, though.

I'm still awaiting concrete examples that are different than those 
banking examples that provide much of the background for my premises. In 
any case, it shouldn't matter if you are trying to understand. Adopt my 
assumptions arbitrarily if it helps you see the ideas more clearly and I 
can provide the documentation later. I think that if you explore the 
real world you'll see that my assumptions hold.

I hope this helps. I really appreciate your specific and forceful 
questions — I think it helps me communicate my ideas more concretely.
Posted by Sean DeNigris (Guest)
on 19.02.2010 21:25
(Received via mailing list)
It seems like everyone's saying the same thing, just not agreeing on
the vocabulary.

When I think about accounts, of course, not being in the financial
industry, I think of withdrawals, AMTs, balances, etc.  And if we were
implementing a system just to cater to stakeholders like me, account
may very well be a domain object.

Now, consider the above as one view into the data of an entire bank.
This is one specific high-level view of the data.  It builds upon a
lower-level view of transaction logs which is necessary to support
other stakeholders - say auditors.

Because we are separating the concrete objects from their roles in the
different contexts, in the 1st context - yes, I'm going to call it an
Account, and as far as I'm concerned, that's exactly what it is; it
appears to be an object that "has" a balance, etc.

However, when I link up actual objects into my context, I won't find
an Account Object.  At some point, someone will have to build code on
top of the transaction log code, to give me the interface I need.  In
DCI, it seems this would be a CustomerAccountContext, or
AdjustAccountBalanceContext, or something similar.

A great term that I've heard JOC and Dan North (who invented BDD -
amazing and relevant stuff that will help you understanding this) use
is "Turtles all the way down."  You implement one layer or view using
words that make sense at that level, and then the next layer down, you
use totally different vocabulary to describe the same objects/
behaviors with that layer's terminology, and so on...  In DCI, it
seems that what you hit are the underlying domain objects - the lowest
common denominator objects that are at the core of the entire system.

Does that make sense?

Sean