Behavior driven service development
Tags: java, eventdriven, microservices
Published: 2021-07-30 13:19:21

I just released version v2.0 of the [requirements as code](https://github.com/bertilmuth/requirementsascode) library.

Using it, you can create a single behavior that receives messages from the calling code. The behavior then dispatches the messages to an appropriate message handler. Which handler is appropriate is defined in a behavior model.

In the following example, a user sends a request with the user name (“Joe”). The system greets the user with “Hello, Joe.”

``` java
package helloworld;

import java.util.function.Consumer;

import org.requirementsascode.Behavior;
import org.requirementsascode.BehaviorModel;
import org.requirementsascode.Model;
import org.requirementsascode.StatelessBehavior;

public class HelloUser {
  public static void main(String[] args) {
    GreeterModel greeterModel = new GreeterModel(HelloUser::sayHello);
    Behavior greeter = StatelessBehavior.of(greeterModel);
    greeter.reactTo(new SayHelloRequest("Joe"));
  }
  
  private static void sayHello(SayHelloRequest requestsHello) {
    System.out.println("Hello, " + requestsHello.getUserName() + ".");
  }
}

class GreeterModel implements BehaviorModel {
  private final Consumer<SayHelloRequest> sayHello;

  public GreeterModel(Consumer<SayHelloRequest> sayHello) {
    this.sayHello = sayHello;
  }

  @Override
  public Model model() {
    Model model = Model.builder()
      .user(SayHelloRequest.class).system(sayHello)
    .build();
    return model;
  }
}

class SayHelloRequest {
  private final String userName;

  public SayHelloRequest(String userName) {
    this.userName = userName;
  }

  public String getUserName() {
    return userName;
  }
}
```

Since the behavior is the central point of control for all functions, you can inject and configure the dependencies of all functions through it. That makes it easy to [implement a hexagonal architecture](https://dev.to/bertilmuth/implementing-a-hexagonal-architecture-1kgf) or clean architecture.

The [following example](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeexamples/helloworld/src/main/java/cleanarchitecture/CleanArchitectureOutline.java) shows how to implement a clean architecure with requirements as code, in principle:

``` java
public class CleanArchitectureOutline {
  public static void main(String[] args) {
    ConsolePrinter consolePrinter = new ConsolePrinter(); 
    GreetingServiceModel greetingServiceModel = new GreetingServiceModel(consolePrinter);
    Behavior greetingService = StatelessBehavior.of(greetingServiceModel);
    
    greetingService.reactTo(new SayHelloRequest("Joe"));
  }
}

/**
 * The behavior model defines that a consumer reacts to SayHelloRequest.
 * 
 * @author b_muth
 *
 */
class GreetingServiceModel implements BehaviorModel {
  private final Consumer<String> outputPort;

  public GreetingServiceModel(Consumer<String> outputPort) {
    this.outputPort = outputPort;
  }
  
  @Override
  public Model model() {
    Model model = Model.builder()
      .user(SayHelloRequest.class).system(sayHello())
    .build();
    return model;
  }
  
  private SayHello sayHello() {
    return new SayHello(outputPort);
  }
}

/**
 * Command class
 */
class SayHelloRequest {
  private final String userName;

  public SayHelloRequest(String userName) {
    this.userName = userName;
  }

  public String getUserName() {
    return userName;
  }
}

/**
 * Message handler
 */
class SayHello implements Consumer<SayHelloRequest> {
  private final Consumer<String> outputPort;

  public SayHello(Consumer<String> outputPort) {
    this.outputPort = outputPort;
  }

  public void accept(SayHelloRequest requestHello) {
    String greeting = Greeting.forUser(requestHello.getUserName());
    outputPort.accept(greeting);
  }
}

/**
 * Infrastructure class
 */
class ConsolePrinter implements Consumer<String>{
  public void accept(String message) {
    System.out.println(message);
  }
}

/**
 * Domain class
 */
class Greeting {
  public static String forUser(String userName) {
    return "Hello, " + userName + ".";
  }
}
```

I think about writing an article about a new, modern approach to clean architecture soon. My goal is to further simplify the development of a service with a clean architecture in a Spring environment.

Are you interested? Tell me what you think in the comments.