Skip to main content

Cred: Idealism as Pragmatism

A Second Preamble: Tangible Cred as playground of vision

"Simplitatea este (...), în general, o complexitate rezolvată" - "Simplicity is, generally, a resolved complexity" - Constantin Brâncuși

The above quote is about art, but it is the author's (and hopefully the reader's) conviction that a man of Software is and has, as the name implies, a tender side to him or her that is part of their internal drive towards software. While not as fecund as true artists, the writer of Software has and uses their artistic drive as part of the full-being experience of "doing" software; we are not terribly special in this regard - any masterfully, soulfully executed craft necessitates this of its craftsman.

Why the quote about complexity? If one has done any reading at all about software, one will very likely have read that one of the greatest parts of writing software is the management of complexity.

In our lived reality, complexity "manages itself" - the farmer, the miller, the baker, the carriageman, the sack-weaver, and every other "component" that leads to bread being made in the village is part of an otherwise infinitely complex system, which in reality "simply exists". It might sound like a silly comparison, but Creation "renders itself" before our eyes with no effort on our part; when we take the task of rendering even fraction of its perceived beauty on a computer screen, the game of complexity is on.

In the same way, any software system that "renders" a system from reality onto a digital frame will engage us in the game of complexity.

However, this complexity can be "resolved", and resolved complexity is simplicity. Here is an example of "resolved complexity" from Tangible Cred:

Handler for reporting Earnings to Endpoints as soon as they are created
class ReportEarningToEndpointsOnTheFlyHandler implements ICommandHandler {

public function __construct(
private readonly IEndpointDefinitionRepository $endpoint_repo,
private readonly EarningsLicensesDataComposerService $ea_composer_service,
private readonly EndpointReportingService $endpoint_service,
private readonly ReportFilteringService $filtering_service,
) {
}
/**
* @throws ApplicationException
* @throws UnimplementedException
* @throws InvariantException
*/
public function handle(ICommand $command): void {
if ( !$command instanceof ReportEarningToEndpointsOnTheFlyCommand ) {
throw new ApplicationException('Invalid command type given to command handler');
}

$ea_datas = $this->ea_composer_service->get_full_dataviews_for_ea_ids( new IntList( [ $command->earning_id ] ) );

$endpoints = $this->endpoint_repo->get_endpoints_by_schedule(EndpointDefinitionSendingSchedule::on_the_fly);
// Presume for the sake of sanity that this executes in one request and the TCred user hasn't yolo-ed 500 endpoints
foreach( $endpoints as $endpoint ) {
if( $this->filtering_service->matches_ea( $ea_datas->current()->ea_self, $endpoint->get_filter() ) ) {
$this->endpoint_service->send_report($endpoint, $ea_datas);
}
}

}
}

Without explaining anything about Tangible Cred does, without explaining any architectural commitment whatsoever, I believe this code is fairly easy to read even for a non-programmer (most important for us - a "tech" manager who knows something about coding).

We retrieve datas formatted in some fashion from a service that takes a list of IDs, we retrieve all "on the fly" endpoints, and a "filtering service" tells us is the Earning in question matches what the Endpoint expects. Then, we ask the Endpoint Service to send a report about the earning.

We naturally understand that:

  • The Command object contains the ID of one Earning (whatever that, Earning, is)
  • A Command "Handler" is similar in name to a simple Command, which it "consumes"
  • The Composer Service expects data on a number of Earnings, but we're providing only one, making sure it's an integer
  • An Endpoint has a schedule; the "repository" knows how to retrieve those Endpoints whose "schedule" is "on the fly"
  • An Endpoint has a "filter"; the "Filtering Service" knows how to check for a yay or nay from the Endpoint's filtering criteria
  • An Endpoint Service "sends a report" based on an Endpoint, and a number of "formatted", or "composed" entries
Details

For the advanced reader While this code is "fine", we might be accused of two instances of a Domain-Driven Design crime, we'll try to preempt them in a question-answer manner:

  • Q: Why do we need a service to "filter" things, can't the "filter", well, filter? Isn't this an anemic domain model?
    • A: The Filter property on the Endpoint Definition is just a collection of integer lists. It would be a crime to let either the Endpoint or the Filter access the Database. Same goes for the Endpoint Service; it would be a crime to let an aggregate itself cURL/remote post.
  • Q: Why does your filtering service accept an "IntList"? Why not a list of concrete IDs, such as EarningIdList? Your code has primitive obsession!
    • A: Yes, we have a degree of "primitive obsession", but it's an architectural compromise we've made deliberately. We're pretty judicious about how our integers reach the Application layer and we try to provide reasonable error paths in case nonsense IDs hit the Command Handlers.

The code is not final - we've acknowledged that we might have a problem if the user has configured hundreds of endpoints, but other than that it feels for most readers of this code that we're doing something simple (not easy, simple!), something that can be grasped from the dance of verbs and nouns on the screen.

Also, at the point of writing this the above code is some of the tersest, the purest in the application. It took a lot of thought and anguish to reach a point where the full intent of an important part of the application can be expressed through ten or so lines of code. This is why the title of this section stands - the end product of fully, properly processed complexity should be something that looks simple, something that should "read itself to you".

We own up to the reality that our code is not final, and that we have made architectural compromises; our idealism is pragmatic, in the sense that, should the reader be persuaded that what he's reading is a bunch of much ado about nothing, our end point is good code, our end point is extensible architecture, our end point is easily treaceable bugs by the very nature of the code that we've written. We are not applying patterns out of a book (or multiple books) to make our code look smart and to secure our jobs - we are uplifting our culture by means of a re-enchantment of sterile business documents into meaningful, meaning-laden ordered worlds.

Endpoints have filtering criteria and are configured with a particular schedule in mind. Earnings have ancillary data that must be compiled before sending away. Our application sends Earnings to configuration-rich Endpoints in a discriminated manner.

The above doesn't sound awfully meaning-laden, but it's "good enough" from just a few lines without context. We'll see in the following sections the mini-cosmos of actors in our applications. Allons-y!