{"id":30536531,"url":"https://github.com/bertilmuth/requirementsascode","last_synced_at":"2025-08-27T16:29:16.367Z","repository":{"id":57740029,"uuid":"69363264","full_name":"bertilmuth/requirementsascode","owner":"bertilmuth","description":"Behavior driven service development.","archived":false,"fork":false,"pushed_at":"2021-12-18T12:32:30.000Z","size":2819,"stargazers_count":159,"open_issues_count":1,"forks_count":22,"subscribers_count":10,"default_branch":"master","last_synced_at":"2023-11-07T15:55:21.360Z","etag":null,"topics":["behavior","behavior-driven-development","event-driven","java","living-documentation","message-driven"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bertilmuth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-27T14:06:22.000Z","updated_at":"2023-06-01T23:31:54.000Z","dependencies_parsed_at":"2022-08-30T10:51:19.583Z","dependency_job_id":null,"html_url":"https://github.com/bertilmuth/requirementsascode","commit_stats":null,"previous_names":[],"tags_count":14,"template":null,"template_full_name":null,"purl":"pkg:github/bertilmuth/requirementsascode","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertilmuth%2Frequirementsascode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertilmuth%2Frequirementsascode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertilmuth%2Frequirementsascode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertilmuth%2Frequirementsascode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bertilmuth","download_url":"https://codeload.github.com/bertilmuth/requirementsascode/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bertilmuth%2Frequirementsascode/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272350792,"owners_count":24919282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-27T02:00:09.397Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["behavior","behavior-driven-development","event-driven","java","living-documentation","message-driven"],"created_at":"2025-08-27T16:29:15.151Z","updated_at":"2025-08-27T16:29:16.348Z","avatar_url":"https://github.com/bertilmuth.png","language":"Java","readme":"# Requirements as code \n[![Gitter](https://badges.gitter.im/requirementsascode/community.svg)](https://gitter.im/requirementsascode/community?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\n![requirements as code logo](./requirementsascode_logo.png)\n\nA *behavior* is configured by a behavior model.\n\nA *behavior model* maps message types to message handlers.\n\nA *message handler* is a function, consumer or supplier of messages.\n\nYour calling code sends messages to the behavior. The behavior finds the right handler. The handler processes the message, and potentially produces a result.\n\nSo the calling code doesn't need to know anything about the internals of your service. It sends all messages to a single behavior instance, and gets a result back. Black box behavior.\n\nSince 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 ports \u0026 adapters architecture. The [Behavior](https://github.com/bertilmuth/requirementsascode/blob/master/requirementsascodecore/src/main/java/org/requirementsascode/Behavior.java) interface acts as the single driver port.\n\nHaving a central place also enables you to deal with cross-cutting concerns, like database transactions and logging. You can keep those concerns separate from your business functions, and change them without affecting those.\n\nThis page describes how to get started. Learn how to create a stateless behavior that handles each message individually.\n\nFor sequences of interactions, create an actor instead. An actor runs a use case model with flows. It remembers the current position in the flow, and accepts or rejects messages depending on that position. Thus, an actor can serve as an easy to understand alternative to state machines.\n\nSee this [wiki page](https://github.com/bertilmuth/requirementsascode/wiki/Actors,-use-cases-and-flows) for an explanation of actors, use cases and flows. You can find more code examples for actors [here](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeexamples/helloworld).\n\n## Getting started\nRequirements as code is available on Maven Central.\n\nThe size of the core jar file is around 100 kBytes. It has no further dependencies.\n\nIf you are using Maven, include the following in your POM, to use the core:\n\n``` xml\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.requirementsascode\u003c/groupId\u003e\n    \u003cartifactId\u003erequirementsascodecore\u003c/artifactId\u003e\n    \u003cversion\u003e2.0\u003c/version\u003e\n  \u003c/dependency\u003e\n```\n\nIf you are using Gradle, include the following in your build.gradle, to use the core:\n\n```\nimplementation 'org.requirementsascode:requirementsascodecore:2.0'\n```\n\nAt least Java 8 is required to use requirements as code, download and install it if necessary.\n\n## How to create a behavior and send messages to it\nLet's look at the general steps first.\nAfter that, you'll see a concrete code example.\n\n### Step 1: Create a behavior model\n``` java\nclass MyBehaviorModel implements BehaviorModel{\n  @Override\n  public Model model() {\n    Model model = Model.builder()\n      .user(/* command class */).system(/* command handler*/)\n      .user(..).system(...)\n      ...\n    .build();\n    return model;\n  }\n}\n...\n\n```\nFor handling commands, the message handler has a `Consumer\u003cT\u003e` or `Runnable` type, where T is the message class.\nFor handling queries, use `.systemPublish` instead of `.system`, and the message handler has a `Function\u003cT, U\u003e` type.\nFor handling events, use `.on()` instead of `.user()`.\nFor handling exceptions, use the specific exception's class or `Throwable.class` as parameter of `.on()`.\n\nUse `.condition()` before `.user()`/`.on()` to define an additional precondition that must be fulfilled.\nYou can also use `condition(...)` without `.user()`/`.on()`, meaning: execute at the beginning of the run, or after an interaction, if the condition is fulfilled.\nUse `.step(...)` before `.user()`/`.on()` to explicitly name the step - otherwise the steps are named S1, S2, S3...\n\nThe order of `user(..).system(...)` statements has no significance here.\n\n### Step 2: Create a behavior based on the model\n``` java\nBehaviorModel myBehaviorModel = new MyBehaviorModel(...);\nBehavior myBehavior = StatelessBehavior.of(myBehaviorModel);\n```\n\n### Step 3: Send a message to the behavior\n``` java\nOptional\u003cT\u003e queryResultOrEvent = myBehavior.reactTo(\u003cMessage POJO Object\u003e);\n```\n\nInstead of T, use the type you expect to be published. Note that `reactTo()` casts to that type, so if you don't know it, use `Object` for T.\nIf an unchecked exception is thrown in one of the handler methods, `reactTo()` will rethrow it.\nThe call to `reactTo()` is synchronous.\n\n## Code example\n[Here](https://github.com/bertilmuth/requirementsascode/blob/master/requirementsascodeexamples/helloworld/src/main/java/helloworld/HelloUser.java)'s a behavior with a single interaction.\n\nThe user sends a request with the user name (\"Joe\"). The system says hello (\"Hello, Joe.\")\n\n``` java\npackage helloworld;\n\nimport java.util.function.Consumer;\n\nimport org.requirementsascode.Behavior;\nimport org.requirementsascode.BehaviorModel;\nimport org.requirementsascode.Model;\nimport org.requirementsascode.StatelessBehavior;\n\npublic class HelloUser {\n  public static void main(String[] args) {\n    GreeterModel greeterModel = new GreeterModel(HelloUser::sayHello);\n    Behavior greeter = StatelessBehavior.of(greeterModel);\n    greeter.reactTo(new SayHelloRequest(\"Joe\"));\n  }\n  \n  private static void sayHello(SayHelloRequest requestsHello) {\n    System.out.println(\"Hello, \" + requestsHello.getUserName() + \".\");\n  }\n}\n\nclass GreeterModel implements BehaviorModel {\n  private final Consumer\u003cSayHelloRequest\u003e sayHello;\n\n  public GreeterModel(Consumer\u003cSayHelloRequest\u003e sayHello) {\n    this.sayHello = sayHello;\n  }\n\n  @Override\n  public Model model() {\n    Model model = Model.builder()\n      .user(SayHelloRequest.class).system(sayHello)\n    .build();\n    return model;\n  }\n}\n\nclass SayHelloRequest {\n  private final String userName;\n\n  public SayHelloRequest(String userName) {\n    this.userName = userName;\n  }\n\n  public String getUserName() {\n    return userName;\n  }\n}\n```\n\n## Further documentation of requirements as code\n* [Examples for building/running use case models with flows](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeexamples/helloworld)\n* [Cross-cutting concerns example](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeexamples/crosscuttingconcerns)\n* [How to generate documentation from models](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeextract)\n\n## Publications\n* [Implementing a ports \u0026 adapters architecture](https://dev.to/bertilmuth/implementing-a-hexagonal-architecture-1kgf)\n* [Kissing the state machine goodbye](https://dev.to/bertilmuth/kissing-the-state-machine-goodbye-34n9)\n* [The truth is in the code](https://medium.freecodecamp.org/the-truth-is-in-the-code-86a712362c99)\n\n## Subprojects\n* [requirements as code core](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodecore): create and run models. \n* [requirements as code extract](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeextract): generate documentation from the models (or any other textual artifact).\n* [requirements as code examples](https://github.com/bertilmuth/requirementsascode/tree/master/requirementsascodeexamples): example projects illustrating the use of requirements as code.\n\n## Build from sources\nUse Java \u003e= 11 and the project's gradle wrapper to build from sources.\n\n## Related topics\n* The work of Ivar Jacobson on Use Cases. As an example, have a look at [Use Case 2.0](https://www.ivarjacobson.com/publications/white-papers/use-case-ebook).\n* The work of Alistair Cockburn on Use Cases, specifically the different goal levels. Look [here](http://alistair.cockburn.us/Use+case+fundamentals) to get started, or read the book \"Writing Effective Use Cases\".\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbertilmuth%2Frequirementsascode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbertilmuth%2Frequirementsascode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbertilmuth%2Frequirementsascode/lists"}