I am responsible for a software project for a few years now (a Java desktop application, which is mostly event-driven). I started it from scratch, and at the beginning of this project I made some strong choices on the architecture of the software.

My architecture

I introduced the Module class, which represents a functionnal part of the application, with a well-defined responsability. The only thing a Module exposes to the world is a set of "communication handles". There are 4 types of communication handles :

  • an Emitter<T> can emit a message of type T.
  • a Handler<T> can receive a message of type T
  • a Puller<R, Q> can make a query represented by a message of type Q, and will receive a response message of type R
  • a PullServer<R, Q> can receive a query represented by a message of type Q and will send back a response message of type R.

Then, at the beginning of the execution of the application, I instanciate all the modules that compose the application, and I set up all the connections between them. An Emitter can be linked to one or many Handlers, and a PullServer can serve one or many Pullers (the types of these two endpoints must be compatible, of course).

All the classes used to represent a message are immutable, and are defined in one subproject. Every Module depends on that subproject, and nothing more. This makes the Modules very decoupled (a Module knows nothing about the other Modules, and their input/output to the outside world very clear). Also, the dynamic aspect of the application (the dataflow) is defined in a unique place, in the main function. Also, it is super easy to test a Module, we just have to provide fake Emitters and PullServers, and plug it to the Module's Handlers and Pullers.

My thoughts on this architecture

So, this is the first "big" software project I work on, and I made up this design because it felt like the right thing to do. Now, the project is working just fine, with a total of 57 Modules working together.

One of my co-worker, who joined the project recently, asked me if this was a common architecture, if there was a name for such a design. I don't have an answer, since I am not really familiar with other real-world software architectures.

It seems to me that this design is close the the concept of Actors, that we can find in languages such as Scala (and maybe Erlang). However, Actors do not provide the decoupling provided by my design. And Actors have an additional capability : each Actor has its own message queue, and its own thread of execution (kind of).

Also, I think my design is somewhat related to the Dependency Injection pattern, in the sense that dependencies between the Modules are defined in a central place. However, this pattern deals with interfaces, not with messages. It does not define how the modules communicate (notification, request/response).

The question (finally !)

Do you know of a software project that's architecture is similar to mine? Is there a name for that?

Edit

@Doc Brown suggests that this design is similar to the Flow Design. I cannot agree more. Here is a one to one comparision between those two designs :

  • My Module is the same thing as a Functionnal Unit.
  • My Emitter/Handler are the same as the Output-pin/Input-pin, except mine don't have a name. In my design, the "communication handles" are only identified by their types.
  • The connections between my Modules is the equivalent of their wires.
  • My Puller/PullServer is similar to their Dependency relations. However, they say there is an explicit dependency from the caller to the callee. In my design they are decoupled.
  • They define the concept of Boards. That's interesting, I think I'll borrow this idea !
  • They define the concept of Configuration. I do have the need for configuring a Module in my program, and for that I define a configuration Handler on some of my Modules.
  • Both solutions are synchronous.
  • I don't have the concept of map and join. But I don't feel the need for it.

Well found, Doc !

没有正确的解决方案

许可以下: CC-BY-SA归因
scroll top