Friday, 9 August 2019

What is The OO Matrix?

Morpheus: I've seen an agent punch holes in designs with only a single dependency. Developers have fought against them with APIs that resulted in nothing but limitations. Yet their strength and their speed are still based in a world that is built on coupling. Because of that, they will never be able to write as simple or as fast code as you can.

Neo: What are you trying to tell me, that I can design objects for easy refactoring within applications?

Morpheus: No, Neo. I'm trying to tell you that when you're ready, you won't have to.

Take the red pill. Read on and I show you how deep The OO Matrix goes...


In my opinion, The OO Matrix is what happened to Object Orientation when the interfacing of objects devolved to the method.

As per my other article Inversion of (Coupling) Control, there are 5 caller coupling aspects to the method.
  1. Return type
  2. Method name
  3. Variable number of parameters
  4. Variable number of exceptions
  5. Executing thread
This method based object interaction is a long way away from the intended message passing vision by Alan Kay (as I understand the history).  Typically, we have envisioned Object Orientation to look as follows, with nice round objects linked by lines:



However, objects interacting via methods have very different shapes.  The variability of the method coupling has objects look a lot more like jigsaw pieces.  The connectors are not simple lines, but complex methods that shape the object differently:



Piecing these method interfacing objects together forms a rigid jigsaw.  This rigid jigsaw is difficult to refactor due to all the coupling.  The result is The OO Matrix:

 

With the birth of Java in the 90's and the ratification of the C++ standard in the same decade, "it is not without a sense of irony" that the Matrix film came out about the same time we locked ourselves into programming within The OO Matrix.  Some of us may sense it's existence with refactoring frustrations, while others grew up in it knowing no difference.

The OO Matrix exists all around our programming coupling us to the machine.  If we consider:
  • the method represents pushing/popping state on/off the thread stack
  • the thread stack represents execution by machines
  • then designing interfaces based in methods is binding us to the machines
  • and as such we perpetuate The OO Matrix

And really, where in the real world do we find a thread stack? Object Orientation was derived from chemical reactions. Businesses operate in message passing (e.g. emails and documents). Even my understanding of our brains is built on message passing. In other words, thread stacks are a machine based construct. Using the thread stack derived method for object interaction binds us into the machine - The OO Matrix.

See my other articles on First-Class Procedures and Local Microservices about how we can break free from The OO Matrix.  These articles demonstrate using messages to interface between objects (i.e. single parameter unnamed methods). This breaks us free from the method, the thread stack, and subsequently freeing our code from machines - The OO Matrix.

Well, this is how I like to describe it - as it's a pretty dry topic otherwise!

But I certainly cry about all those hours (if not days/weeks) of refactoring code in my life due to the method coupling problem.  Especially, as if we followed Alan Kay's vision of focusing on message passing, this should never have been a problem.  And to me, this may actually be a more expensive mistake than null.

Monday, 1 July 2019

DDD Perth 2019 Preview


This article is a little taster to wet your appetite regarding my talk at DDD Perth 2019.  Given there are 6 tracks competing for your attention, I'm just here to say that if you have a technical inclination don't miss:

Dependency Injection is only 1/5 of the Inversion of Control problem






First of all, the presentation is full of Matrix references.  You get to geek out on not only the latest in tech patterns, but do it with lots of Sci-Fi references.  Plus the Matrix is a great analogy for my talk, as I show you what is the OO Matrix.

Yes, the OO Matrix is very real if you write any mainstream OO languages (and even functional languages).  You are all plugged into it!   Some of you, like Neo, may sense it's existence.   Others of you grew up in it, knowing no difference!  History even has some sense of irony that the Matrix film came out around the time the OO Matrix plugged us all in.   I will show you what it is and there is no going back, once you see it.  Get ready to swallow the "red pill" and join me in Zion.

And if that alone does not entice you enough, then get the "geek credit" for being present at the first talk where I introduce:
  • Continuation Injection
  • Thread Injection
If you think Dependency Injection shaped much of mainstream development, then you'll be able to tell your co-workers, new interns, even your kids that you were present when Continuation Injection and Thread Injection were first announced at a conference!

You may think Inversion of Control and Dependency Injection are dry topics.   I assure you will be far from bored, and I'll leave you like you did walking out of the Matrix. In the words of Keanu Reeves....   "WHOA"!



Wednesday, 19 June 2019

Local Microservices: First-Class Procedures

This is the third article in a three part series on local microservices.  The first two articles looked at:
These articles identified the method coupling of Object Orientation creates a monolithic jigsaw of different shaped objects.  Microservices are breaking these into more manageable, smaller jigsaws that appear similar in shape.

This article continues the breaking down to consider local (pass by reference) microservices.

Part Three: Local Microservices via First-Class Procedures

The first two articles in this series identified:
  1. Object references are a nice graph of nodes (objects) and lines (fields)
  2. Object methods have a significant coupling problem creating a jigsaw of behaviour
  3. Microservices break the method couple to return behaviour to a graph of nodes (microservices) and lines (HTTP requests, / Queue messages)
There is an underlying pattern to representing this decoupled behaviour.   It is HTTP URL / Queue name and payload / message type.   This decoupled client calling pattern can be represented with the following general interface:

interface ClientCall<T> {
  void invokeService(T singleObject);
}

This client calling interface is then implemented by the appropriate HTTP request service(...) method or Queue onMessage(...) method.  These methods are usually found on the following objects:

public void SomeHttpServicerImpl {
  @Inject SomeRepository someRepository;
  @Inject AnotherRepository anotherRepository;
  @Inject ClientCall<SomeArgument> anotherMicroservice;
  // other dependencies

  public void service(SomeObject httpRequestEntity) {
    // service HTTP request with injected dependencies
  }
}
public void SomeQueueConsumerImpl {
  @Inject SomeRepository someRepository;
  @Inject AnotherRepository anotherRepository;
  @Inject ClientCall<SomeArgument> anotherMicroservice;
  // other dependencies

  public void onMessage(SomeQueueMessage message) {
    // service Queue message with injected dependencies
  }
}

Furthermore, what is not shown clearly is the threading model.   As the HTTP servicer or Queue consumer are in their own process, they are run with their own threads.

The result is the following pattern for implementing the microservice:
  • Single object provided by client
  • Remaining objects are dependency injected
  • Thread used is based on service/consumer implementation
  • Interaction with other microservices is via single parameter ClientCall
The issue with this pattern is that all calls to other microservices require the microservice to be executed by another thread.  As the mciroservice resides behind HTTP requests / Queues, there is process boundaries preventing the calling thread from executing the microservice.

The process boundary separation provides a bounded context, so that the microservices are isolated from each other.  However, this separation puts a lot of communication overheads and network error handling into microservice solutions.  Plus it disallows microservices from being executed by the same thread.

So can we have the microservice called and executed by the same thread, and still continue to provide the microservice advantages of bounded contexts?  (in other words, the smaller jigsaws)

Local Bounded Context

To see how local (same thread calling/executing) microservices can be achieved, we need to transform the above implementations slightly.

Rather than field/setter injection, let's look at using constructor injection.  We could turn the above implementation into the following:

public void SomeMicroserviceImpl {
  private final SomeRepository someRepository;
  private final AnotherRepository anotherRepository;
  private final ClientCall<SomeArgument> anotherMicroservice;

  @Inject
  public SomeMicroserviceImpl(
            SomeRepository someRepository,
            AnotherRepository anotherRepository,
            ClientCall<SomeArgument> anotherMicroservice) {
    this.someRepository = someRepository;
    this.anotherRepository = anotherRepository;
    this.anotherMicroservice = anotherMicroservice;
  }

  public void service(SomeObject httpRequestEntity) {
    // service HTTP request with injected dependencies
  }
}

However, that's a lot of code!

Rather, why not just inject the dependencies directly into the method:

  public static void service(
            SomeObject httpRequestEntity,
            SomeRepository someRepository,
            AnotherRepository anotherRepository,
            ClientCall<SomeArgument> anotherMicroservice) {
    // service HTTP request with injected dependencies
  }

The method has effectively become a procedure.   The object and all it's fields are no longer necessary.  The above procedure links the required objects together by being parameters.

This execution is now:
  1. ClientCall used to invoke a procedure
  2. Procedure pulls in appropriate dependencies
  3. Procedure then invokes other procedures via the ClientCall interface
The execution is no longer methods navigating the Object references, locking you into monolithic jigsaw.  It is now procedures invoking each other, pulling in only the required dependencies for the procedure.

As the procedure pulls in only its required objects, it provides a bounded context.  One procedure may pull in a particular set of objects, while another procedure may pull in a totally different set of objects. As the procedure joins the objects, we no longer have to create a big graph of all objects referencing each other.   We can separate the objects into smaller graphs.  This break down allows separation of objects into bounded contexts.

Now the question comes of how can we implement this so the procedures run within the same process space?

First-Class Procedure

Well this procedure is remarkably similar to the First-Class Procedure.  See:
What the First-Class Procedures allows is containerising small snippets of logic within a procedure.  These procedures communicate via loosely coupled continuations that require only a single object (payload message).  The remaining objects are dependency injected.  Furthermore, threading models can be specific to each procedure.

The two bounded context approaches have similar characteristics:
  • HTTP/Queue communication can be considered a single argument Continuation
  • Threading models can be different within each first-class procedure / microservice process
  • Dependency Injection of both allows access to only the required object graph allowing smaller object jigsaw puzzles (no monoliths).  In other words, bounded contexts.
The difference is that the same thread can call and execute the First-Class Procedure.  In other words, First-Class Procedures run locally with each other.

Remote vs Local

But don't microservices want to be process separated to allow different release cycles and scalability?
Yes, that is absolutely true once up and running in production with heavy load of users.  However, what about getting started with microservices?

For me this falls into the problem of being opinionated too early.  To get the right mix of microservices takes a significant amount of requirements gathering and architecture.  Why? Because refactoring microservice architectures can be expensive.  Microservices involve a lot of overhead in typically different code repositories, build pipelines, network failure handling, etc.  Finding you got the microservice mix wrong involves a lot of effort to change.

By starting out with first-class procedures, you get to try a local microservice mix.  If the mixture is wrong, it is very quick to change them.  First-class procedures are weaved together graphically.  Therefore, to change the mixture is simply rewriting the procedures and then drawing the new connections between them. Yep, that's it.  No code moving between repositories.  No changing build pipelines.  No extra error handling because of network failures.  You can get on with trying out various mixes of local microservices (first-class procedures) all on your local development machine.

Once you find a mix you are happy with, deploy all of them in the one container.  Why?  Because unless you have a large user based, you can run your first-class procedures in just one node (possibly two for redundancy).  Having less deployed nodes, means less cloud instances.  Less cloud instances, is well less dollars.

Then as your load increases, you can split out the first-class procedures into separate nodes.  Just change the continuation link between them to either a HTTP call or Queue.  Furthermore, this split can then be for various reasons you may discover along the way:
  • differing functionality change cycles
  • differing team responsibilities (e.g. Conway's Law)
  • data governance may mean geographic restrictions
  • security may require some to run on premise
  • on premise capacity limits may mean pushing some to public clouds
The above is not an exhaustive list.

Having to requirements gather and architect the microservice mix given all of the above could get quite exhausting.  Especially, as some aspects are quite fluid (e.g. teams change, companies buying other companies, capacity limits on in house data centres, etc).  There are significant factors making it difficult to find the right mix of microservices up front.

Plus this also works in reverse.  As things change and some aspects don't experience higher loads or significant functional changes, they can be combined back into single instances.  This reduces the number of cloud instances required, and again reduces dollars.

Summary

For me, local microservices (i.e. pass by reference mircoservices) is going to eventuate.  This is similar to session EJBs being introduced because the EJB 1.0 specification of only remote calls was just too heavy.  Yes, we have better infrastructure and networks than 20 years ago.  However, the financial overhead costs of only remote microservices may soon be considered heavy weight and expensive given that local (pass by reference) First-Class Procedures are available.

So if you are finding the "remote" microservice architect a heavy weight and expensive consideration, try out First-Class Procedures as a local microservice solution.   This gets you many of the benefits of microservices without the expense.  Then, as your load increases and your revenues increase, scale into a remote microservice architecture.  But this is only where you see real need, so you can keep your infrastructure costs down.

Friday, 7 June 2019

Local Microservices: Breaking up the Jigsaw

This is part two in a three part series looking at local microservices running in the same process.  Part one identified the coupling problems in Object Orientation behaviour (found here).  This article will look at how microservices are helping reduce the coupling problem.

Part Two: Breaking up the Jigsaw

Part one identified that object behaviour coupling is similar to a jigsaw puzzle. This is a highly coupled jigsaw of varying shaped objects. These different shaped objects makes their re-use and refactoring difficult within monolithic applications.

So, you may be asking how are microservices helping this problem?

For me, I see the evolution of microservices to be an evolution to break down the rigid behavioural coupling imposed by object methods.

We had applications grow to become monoliths:


This became unmanageable to enhance or re-use, as everything was tightly coupled together in a rigid jigsaw.

Our first attempts was to try re-using parts of the jigsaw with Service-Orientated Architectures.   This looked like the following:



The service-oriented architecture was, in my opinion, a doomed to failure attempt to the expose method connectors outside the system for re-use.  Yay, we can now call into our monoliths to re-use aspects of them.  Oh, wait there was too much coupling to that method that it was just too hard to separate it from the rest of the monolith.

Ok, we could put in governance and some great coding practices to avoid this.  However:
  • deadlines
  • shortcuts
  • new team members
  • occasional bad design decisions
  • etc 
allows the coupling to increase over time.  As much as we wanted to believe in the ideals, the behaviour coupling of methods just took over to create the monolith jigsaw.

We needed to break things down and keep them isolated.

So we split the jigsaw up into smaller puzzles.  The result is the following smaller puzzles joined by HTTP requests / Queues:


And for me, microservices were born.

At first glance, this looks very similar to the original EJB 1.0 specification of only remote calls.  Now one might argue that microservices are not single objects like EJBs typically were.  This, however, is not why I see microservices an improvement over remote EJBs.

EJBs use remote procedure calls that allow multiple parameters and varying exceptions to be thrown. This does nothing to decouple you from the varying shape of the method call. EJBs only enable methods to be called remotely.  These remote method calls continue to have all the jigsaw coupling issues of method calls.  Except, now they are less reliable due to network failures.  Hence, EJBs suffer the method coupling problems that leads you to a distributed monolithic jigsaw.

Microservices on the other hand, standardised calls to other microservices via HTTP requests / queue messages. Looking at the five coupling aspects of the method call (Inversion of Coupling Control), HTTP requests / queue messages remove most of the method call coupling:

Method Coupling AspectHTTP RequestQueue
Method NameURL

Though, can be decoupled indirection via lookup in service directory/registry
Outbound queue

Provides decoupled indirection to target consumer (via message routing)
Return TypeMay provide return entity.

However, typically this is only for front-ends with users waiting.

Note: be careful of synchronous returns between microservices, as they can create synchronous coupling that can lead to distributed monoliths
N/A, as decoupled from any synchronous return values
ParametersOnly single payload

Typically JSON/XML serialised object.
Only single payload

Typically JSON/XML serialised object.
ExceptionsStandardised REST status codes.

Note: be careful of relying on error response payloads, as they may be indications of cohesiveness problems in the microservice
N/A, as decoupled from any synchronous processing
ThreadingDecoupled as separate process

Any threading model enabling synchronous response
Decoupled as separate process

No restriction on threading model


Therefore, using HTTP requests / queues, the microservice calling shape is effectively standardised. Given the payload is typically a serialised object (e.g. JSON/XML), this removes the ability to pass multiple parameters.  Standardising the HTTP status codes disallows varying exceptions.  Plus, my preferred microservice communication of queues is decoupled by its very nature.

So by making the communication HTTP requests / queue messages, microservices are removing the method coupling problems.  It makes it easier to call different microservices, as the shape is only a name (HTTP URL / Queue name) and a single parameter (payload).

This, actually, is similar to the object reference shape of type and reference discussed in part one.  However, now type is parameter type (payload serialised object) and reference is name (URL / Queue name).  This allows microservice behaviour to somewhat be represented like the idealised object graph at the start of part one - lines to standard shaped microservice call connectors.

Stay tuned for part three where we look at further isolating the microservice container to the servicing method to effectively enable local microservices.

Wednesday, 29 May 2019

Local Microservices: Object Orientation Behaviour Coupling Problem

This is the first in a three part series on looking at creating "local" microservices.

What I mean by local microservices is pass by reference microservices running in the same process.  Right now I see microservices similar to the original EJB 1.0 specification.  All calls between the EJBs were remote, just like microservices are now.  Due to remote call overheads, the EJB 2.0 specification brought in session (local, pass by reference) EJBs running in the same process.

Now, before getting to local microservices, we need to look at identifying the Object Orientation behaviour coupling problem.  This to me, identifies a big problem that microservices resolve.   It is also the reason enabling local microservices.

Part One: Object Orientation Behaviour Coupling Problem

Structurally Object Orientation joins objects together in a very nice graph. These typically look something like the following:


These graphs represent the object relationships in your application.  Each line is a field reference to another object.  This, for example, allows modelling your personal details to have addresses, phone number and various other objects containing information.

However, I can't call an object reference.  I use the object reference to access a method on the object.  Behaviour of your application actually follows the method calls.  In other words, program control follows method calls on the thread stack.  Yes, the object references make methods accessible to be called, however the methods calling each other is how behaviour of your application is achieved.

So, we can just draw the above graph with the methods calls, right?  No, the method coupling is a lot more complicated than just an object reference that varies at most by type (see Inversion of Coupling Control).   Methods have:
  • a particular return type
  • a name
  • varying number of parameters with differing types
  • varying number of exceptions with differing types
  • thread to execute them
Drawing a simple line between objects to represent behavioural relationships (program control flow) does not respect the method coupling complexity.  In the object structural graph, changing a line is simply changing the reference (memory address) to another object.  Yes, restrictions apply based on the type of object referenced, but it is a single address value that couples the two objects into a structural relationship.  This is not the case with methods.

Each method call is a different shape.  In terms of object structural connectors the shape of the object reference is object type and memory address.   This is consistent across all object references.  However, for methods the call (connectors) are different shapes due to the above 5 aspects.  In other words, one method may have 1 parameter, while another has 3 and throws 2 exceptions.  The shape of each method call connector varies significantly.

Drawing the behaviour diagram of object method calls is more akin to the following:


Each call (connector) between the methods is a different shape, just like a jigsaw.

We piece objects together into a jigsaw to achieve the behaviour of the application.  This is why refactoring your application is so difficult.  It's like trying to move pieces of a jigsaw around to make a new picture.   We end up having to change the pieces significantly just so they even attempt to fit into the new picture.

It is also the reason, I believe, why object orientation never provided that ideal class re-use.   Re-using objects is like trying to re-use jigsaw pieces of one puzzle to complete another puzzle.   Now if the puzzles are somewhat alike, you can kinda jam them together.   However, more often than not you have to change the piece (object) to fit into the other jigsaw (application) losing re-use.

Hence, the method coupling problem creates a significant behavioural coupling problem in monolithic Object Oriented systems.  Refactoring is an expensive exercise, as its not redrawing lines between nice round objects.  Refactoring is reshaping pieces to fit into a new jigsaw picture.

Now I can continue the analogy further with much of API development attempting to standardise jigsaw pieces and finding generic pictures that represent majority of systems.  However, I'm hoping you can join me in seeing that much of Object Orientation behaviour coupling problem is not with the objects but rather the use of methods.

And yes, for Object Orientation purists, Object Orientation is more about loosely coupled message passing.  In other words, languages such as Erlang may be more closer to what the intention of Object Orientation really was supposed to be.  However, my focus here is the "mainstream" understanding of Object Orientation being objects and methods.

Stay tuned for my next part on how microservices are helping with relieving the Object Orientation method coupling problem.