Cope
went to visit Trygve for about three days in the beginning of August
and, as usual, there was a
lot of energetic discussion. In addition to the usual fun smoke and
heat, some
light also came out. Here are the major upshots of the week.
Abstraction Layers and the
difference between Restricted and Full OO
Alan
Kay coined the term "object orientation" and likened an object system
to a system having thousands and thousands of computers all hooked
together by
a very fast network. That perspective grounds some of what follows
here. Think
of computer hardware as a programming API. It provides an abstraction
layer. Trygve
and Cope define an abstraction layer as a shared understanding of the
essential behaviors
of an object as seen from a client, while the details of the
implementation are hidden. We
want to follow the
#1 rule of
software design: no surprises. That implies that the hardware can't
reach up
into the software and do unexpected things. If the garbage collector
leaks,
then the hardware doesn't implement a good abstraction layer. It also
implies
that the software can't do things to the hardware. You can generalize
this
concept to layers of software, so the operating system also provides an
abstraction layer.
Trygve is now talking
about "Restricted OO" —
which is OO-as-we-knew-it-before-DCI with restrictions that makes the
code
readable. This in contrast to "Full
OO" which DCI implements. Maybe there will be other ways to
implement
it, too. There is a simple but stunningly powerful difference between
the two and
we spent much collective effort on deepening our understanding of those
perspectives. The
difference is in the programmer's observation point.
Restricted OO
With Restricted OO, the programmer
observes the system from the inside of an object. The class defines what the
programmer can and cannot see. A programmer can
see:
- The state of
an instance as defined by its
class attributes.
- What
messages an instance can receive.
- The methods
that will be triggered by
those messages.
- The attributes
that are changed by
those methods
- The messages
that are and the types
of the objects that will receive those messages.
There are many things the
programmer cannot see by reading the class code. Examples:
- The sender of a received message and the purpose of this message
seen within a wider
context.
- The class of the receiver of a
message sent from an observed object.
The reason for these limitations is that this receiver lives within an abstraction boundary. The programmer cannot know, at compile
time, which behavior will
be invoked at runtime – by design. A programmer can understand the program
behavior only in general terms.
This is an essential part of the "power" of object orientation.
Unrestricted programming with classes — which is OO-as-we-knew-it-before-DCI – can lead
to
unreadable spaghetti code. We call it “Unrestricted OO”.
We spent quite some time
discussing the restrictions needed to get readable code. It appeared to
have
something to do with the abstraction boundary between a client and the
inside
of an object. Perhaps it would be illegal for an execution to cross
back up across
the boundary to do unpredictable things to the client. We did not
conclude and the
work continues. The result shall be a rule that is the “restricted” in
Restricted OO. We hope that Unrestricted OO some time in the future will
be
relegated to history.
Full OO
With Full OO, the
programmer observes the system from the space between the objects. Programmers can see several objects at once and observe
the interaction messages that flow between them. They can’t see inside
the
objects because each lives behind its own abstraction layer boundary. They can't even
know, at compile time, which behavior would be invoked at run time — by
design.
DCI
implements system behavior by pulling together the behavior of a system
operation
into
several co-located roles, each representing an object. The programmer
can see the roles together and
reason about
their end-to-end behavior. The system behavior is explicitly given
by the RoleMethods that are outside any abstraction boundary.
There is still an abstraction barrier:
between the
roles and the objects that play those roles. This barrier has the usual
restriction: The object implementation can't reach up into the
Interaction and
do unexpected things. However, it is a very narrow abstraction layer
whose
operations should be viewed as primitive, and which, by design, always
return.
To be able to reason across a sequence of mutually invoking roles means
to be
able to reason about several objects at once.
Define a compression as a way to represent that information in fewer bits of data than the amount of information it contains, using contextual knowledge that makes it possible to losslessly expand that representation into the original information. In Restricted OO, a
programmer cannot compress the understanding of anything: everything is
an
abstraction, except the current method. There is a large lack of contextualization. In Full OO, RoleMethods are
compressions.
In DCI terms: Data classes are coded with
Restricted OO. Interactions are coded with Full OO.
Restricted OO is very much
like the Atomic Event Architecture of the Lean Architecture book (e.g., a traditional "shapes" OO program, with very simple operations); Full
OO is
like DCI.
We spent a lot of energy
and time on these concepts and feel they will prove useful when
worked out
in detail.
Handoffs
We had a few discussions
about handoffs. In Lean architecture, you want to avoid handoffs, so
there
should be no major (human) communication boundary between Context code and Data code.
This means
that the writer of the code for a Context with its roles and role
methods should
cooperate closely with the writer of the associated Data classes to
adapt the
abstractions to the needs of the system as a whole.
On the other hand, there
are abstractions within abstractions and the transparency of the
abstractions
are reduced down the abstraction hierarchy. (There is no hard-and-fast
rule;
the developers of the first Smalltalk runtime system created private
microcode
for their Alto computer to optimize their system). Theoreticians will
claim that
any interface to an object must be supported by precise definitions of
its
operations with preconditions, postconditions etc.
In some sense, the whole
purpose behind the DCI encapsulation of roles is that they are all in
one place
where they can be considered together without going across an
abstraction
boundary. But with a role method saying self–>something, we
cross an
abstraction boundary and must rely on it being implemented correctly.
(Otherwise, the code of the RoleMethod would be unreadable).
Abstraction boundaries,
therefore, are an agreement based on mutual trust. They are maybe a way of encapsulating
change at
some level. But that isn't a reason to really "hide" the changes.
Everybody, all together, from early on — on everything.
So abstraction boundaries,
rather than being viewed as "don't look here" fences, draw attention
as key points of agreement around crucial architectural issues that the
abstraction boundaries bring into focus.
Context / Role Integration
We agreed it would be a
good idea if every Context could play some kind of Context role. That
would
make it possible to view the Context as a role from inside itself, and
as an
ordinary object from outside itself, thereby providing a smoother
impedance
match across the Context abstraction layer boundary. The Context could
be a
repository for state common to the whole interaction and visible to RoleMethods through its role name,
standardized at e.g., CurrentContext. This idea needs more
work. For
example an
implementation — the true killer of good ideas.
DCI and Systems Complexity
We talked a little about
simple, complicated, complex and chaotic systems (Snowden's taxonomy).
DCI is
interesting because it can implement an adaptive system. It responds to
changes
in its environment, implementing an open system that has a degree of
self-organization. While Restricted OO systems are also open systems,
they
aren't adaptive.
DCI does this by
effectively implementing a weak form of reflection.
Articles
Trygve gave Cope
comments on his Elephant article, first suggesting that it be
re-written from
scratch with more precisely defined concepts. He has later withdrawn
the suggestion since he realized that the entertainment value of the
current
form would be lost with very little gain. Cope
continues to refine the article, and won't do a major upheaval.
Web Site
We have bought FullOO.info
on a Norwegian web hosting
site. Cope is supposed to set that up but is a bit lost right now, partly
because their setup is a bit mysterious. (They already sold us oo.info and after a week of not being able to make it work they admitted a bug in their system that allowed them to sell us a URL that had previously been allocated to someone else.) The main issue seems to be
that though he purchased a URL and 8 gigabytes of storage, we still
don't
appear to have anything with an IP address. There is something wrong
with the hosting site. Trygve will phone them (in Norwegian) and
expect they'll fix the problem quickly. Then we can get down to the
much wanted Q&A section and collect other material that should go
to the site.