Topics

[Edgex-devel] Coupling Between Microservices

Drasko DRASKOVIC <drasko@...>
 

On Fri, Oct 20, 2017 at 1:35 PM, Car, Boran
<Boran.Car@...> wrote:
I think it's time for a Jim moment: "So what I'm hearing is..." etc... to bring some conclusions :).
Jim is wisely waiting that we shoot all our bullets before ;).


Possibly around the line that it's not all black and white, but I'm not going to even try it - I'd probably be a bad replacement.

Tony,

The extra research is quite useful. I would maybe add that strong opinions on either side of the fence meant that someone got burned in the past. Going back to late 90s, early 2000s where the consensus was you create 3 packages, common, client and server and common is shared by both the client and the server in an DRY attempt. I've actually seen that perverted at one of the companies I worked for that had an embedded device connected to PCI/PCIe, the driver and the host side software, and they were all sharing some marshall/unmarshall common C code making it almost impossible to split these 3 things into separate repos (and upstream the driver). Nowadays, we're now more into spec files and generation in order to separate and decouple. But, I digress...

What are your specific opinions on things like the data types, e.g. https://github.com/edgexfoundry/export-domain/blob/master/src/main/java/org/edgexfoundry/domain/export/ExportRegistration.java and https://github.com/edgexfoundry/core-domain/blob/master/src/main/java/org/edgexfoundry/domain/meta/Addressable.java. I was seeing Drasko's point here and raising it by one perhaps - if they're part of the external API, then I'd recommend them generated from a centralized specification and injected or copied or whatever, but also add versioning spice on top. If they're never visible externally, I'd just bluntly duplicate them and let each microservice evolve its own thing from it. And I think newcomer developers might just appreciate that more, knowing that it's only internal to them and they get to change whatever they'd like. It would also send a strong message if they wanted to have that change replicated across multiple microservices that they should probably go to specificatio
n and then generation.

Helping new developers doesn't necessarily mean getting them to link with a shared library. E.g. at Thales e-Security we have that building block template that gives you a nice starting point for writing your business logic by injecting things inside. I would say think of Dependency Injection the Docker/habitus way.
Thanks Boran - both your and Tony's inputs are very useful!

I have been thinking over this problematic, and I am inclined to say
that much of the difficulty comes from the coupling of domains
themselves, not necessarily from the implementation. Actually, EdgeX
code somewhat resembles me as a monolith broken into different repos,
rather then independent set of microservices. And I think that much of
this impressions comes from the nature of these services - these are
not some distinct architectural blocks - like for example pub/sub
broker or database would be, or Redis kv store. When you have these
kind of services, independent and self-sufficient, with different
responsibilities and task in the system and different nature then it
is easy to see clear separations - each of them is run in a separate
container, etc, etc...

However, whole EdgeX system can logically run very well as a monolith
app, and even do we introduce some separation that seems visible -
like between layer that does the export services and the core layer -
still there is reuse of the logic and data - both of these layers work
on the same task practically and I think domain coupling comes from
this logic.

Having in mind this observation, I am not against sharing data models
between these microservices (some minor stuff can be duplicated, but
bigger dependencies would probably fit well in shared libs).

However, this also brings me back to one of my previous topics - monorepo :).

As I mentioned, having shared libs probably is not so bad in this
case, but having data models scattered over different repos can be
confusing. Let's take a concrete eample: you have microservice A that
uses some class, and also service B that use the same class. Where
would you define this class - in repo A or repo B? Or will you create
new repo C to be a meta-repo and hold data models only, these data
models that are used in both A and B.

And this is exactly the approach that Export Services take - both
Export Client (https://github.com/edgexfoundry/export-client) and
Export Distro (https://github.com/edgexfoundry/export-distro) use
models that are because of this fact that both services share them put
in a separate repo called Export Domain
(https://github.com/edgexfoundry/export-domain). And this looks OK so
far - but the problem is that these Java classes in Export Domain
include some references and dependencies on classes defined in EdgeX
Core (https://github.com/edgexfoundry/core-domain), and this is where
the things get a bit ugly, because while so far we were staying in the
same Export layer we now start sharing cross-domain data. But as I
mentioned, I am starting to think that this is actually not even
cross-domain, as these divisions between domains (layers) seem to be
only provisional...

The approach I took to lower the impact of this problem is that I've
put both EdgeX Client and EdgeX distro in the same repo:
https://github.com/drasko/edgex-export. Naturally - EdgeX Domain is
there also. But the good part is that nothing is lost but this move to
a single repo - there is still strong division between code - Client
stuff live in the `client` dir
(https://github.com/drasko/edgex-export/tree/master/client) and distro
stuff in `distro` dir
(https://github.com/drasko/edgex-export/tree/master/distro). Top-level
files hold the shared structures that are used in both client and
distro.

Note that we still have two distinct microservices, completely
independent of each other, built independently and deployed
independently via different Dockerfiles. Elegance of Go just helps us
organize the code better.

Note also - and this is very important - that this code separation
allowed two companies - Mainflux and Cavium - to workd completely
independently on differerent services. Mainflux contributed client
part, while Cavium is working on distro. Having a simple repo actually
help us sync on the common files using PRs and Issues of this GitHub
repo for discussion - for example:
https://github.com/drasko/edgex-export/issues/19 and
https://github.com/drasko/edgex-export/pull/20

In my opinion this speeds up development process and assures higher
quality and integrity of code.

I proposed earlier that we evaluate actually putting all EdgeX Go code
in one single repo, using this model that I proposed in export
servcies and following the practices from Google
(https://www.youtube.com/watch?v=W71BTkUbdqE) or Uber
(https://www.youtube.com/watch?v=lV8-1S28ycM).

But if this is to much integration, we can at least group the layers
that we have today - have separate repos for export, core, supporing
services and device services - just 4 repos for whole EdgeX Go code. I
think that will diminish the impact of shared cross-domain data
models, as all services from the same repo can reuse data defined in
the top-level files of the repo.

My $0.2 and sorry for the longer mail again, could not make it shorter.

Best regards,
Drasko DRASKOVIC
Mainflux Author and Technical Advisor

www.mainflux.com | Industrial IoT Cloud
-------------------------------------------------------------------
Engineering Division | Paris, France

LinkedIn: https://www.linkedin.com/in/draskodraskovic
Twitter: @draskodraskovic