On Nov 12, 9:53 am, Alex Eagle <
aeagle22...@gmail.com> wrote:
> - Data entities may only be composed of other data entities, so we
> have to bootstrap from somewhere. Built-in basic types and collections
> would be known data entities. Does that cover all cases, or do we need
> to let a user mark their own class as a data entity, regardless of
> whether we think it shouldn't be?
In the end, everything reduces to primitives.
> - A data entity can still have a method with high cyclomatic
> complexity (an EmailMessage with a encodeBase64 method, lets say). A
> test might still want to replace it with a MockEmailMessage.
The nice thing about a data object is that it's a deterministic
function of the data it contains and the parameters passed to it. In
my experience, this means mocks would be much less important. The only
way to make mocks unnecessary for data objects is to make data objects
mere containers for data, which is in fact what functional languages
do, but which won't be acceptable to OOP developers.
So the question is, how devastating would it be to allow a user to
directly create a data object? In my opinion, not very: since the data
object cannot interact with any services, all of the methods it
provides are going to be data processing-oriented -- algorithms that
are quite testable and stable, which don't have to deal with complex
service interaction semantics (which is where many errors arise in
large-scale systems).
> If we
> allow directly new'ing a data object, there would be no injection
> point, and you couldn't mock in a test. Maybe the syntax is the same
> as for requesting injection ( EmailMessage m = EmailMessage(); ) but
> the compiler can optimize it to a plain new operation.
That would work.
> - Data entities vs services opens the door for things like
> serialization and equals/hashCode to be done nicely.
Indeed, any data object can have an excellent implementation of
equals, hash code, and serialization. All three are a mess right now
in OOP precisely because classes become data/service hybrids.
> I'd like to serialize data entities straight to Protocol Buffers,
I really like that idea. Language-level support for protocol buffers
would be a real treat.
> - Services can take Data Entities as constructor parameters, so we
> will need a way to request Assisted Injection (the Guice term for an
> element which has some injection points that must be supplied at
> creation time, ie. a factory)
It's also possible to deny services the ability to require data
entities as constructor parameters. This just means data will be
pushed into a data service. Both I think have the same effect in the
end, one just achieves greater unity at the expense of forcing
extraction of data dependencies into services.
> Are you confident that all classes can naturally be expressed in one
> of the 5 entities you listed? I like the idea a lot, so long as we
> don't paint into a corner by over-simplifying the real world.
Functional languages have already demonstrated the ability of a data/
service dichotomy to model anything. In Haskell, for example, the
"services" are type classes, the "implementations" are type class
instances, and the "data" are data declarations (or equivalent).
Bringing these concepts into an object-oriented programming language
would be novel, of course, but as long as the concepts are transferred
to equivalently powerful concepts (or close), then you still have
strong assurance for the language's ability to model anything.
Services as described above are injectable, composable, even
dynamically, can possess a default implementation of some methods
(defined in terms of other methods), and could even support generics.
With these benefits, you're achieving something very close to a hybrid
of ML-style modules and Haskell-style type classes.
Still lots of details to work out, of course, but I feel addressing
the flaws with OOP will in fact bring OOP closer to functional
languages, while still retaining benefits of OOP.
Regards,
John