Skip to main content

Business-as-Code

· 7 min read
Colt McNealy
Managing Member of the LLC

The Infrastructure Software world was revolutionized by Infrastructure-as-Code, which provides observability, governance, and agility to infra teams. Analogous problems in application development are soon to be solved by a new paradigm: Business-as-Code.

info

This is the first part in a three-part series about what makes LittleHorse unique: we are the only platform that allows you write business-as-code for both fast and slow processes, unifying workflows and events.

  1. [This Post] Business-as-Code
  2. [Coming Soon] Fast and Slow Processes
  3. [Coming Soon] Workflows and Events

Business-as-Code allows platform teams to enjoy:

  • Governance and audit trails of who made what change and when.
  • Agility to quickly deploy new infrastructure in compliance with central policies and without fear of breaking systems.
  • Observability and a single place to check what infrastructure and security policies are deployed

While Infrastructure-as-Code has successfully brought governance, predictability, and agility to infrastructure and security, the development of business processes running on distributed applications remains unsolved and is ripe for a new paradigm: Business-as-Code.

Just as infrastructure teams once struggled with manual, error-prone deployments and inconsistent environments before IaC, application development teams today face analogous challenges when composing business processes across distributed systems. The same chaos that IaC solved for infrastructure—scattered configurations, lack of visibility, and brittle manual processes—now plagues how we build and maintain business logic in microservice architectures.

The Cost of Complexity

As I previously wrote, software engineers at the modern enterprise must build applications to support business processes in a highly distributed technical environment. This makes it difficult to deliver stable, working applications and causes significant technical complexity, resulting in a divide between the code engineering teams write versus what the business needs.

Distributed Apps are Hard

In order to make distributed processes reliable, engineers need to spend time on non-differentiated yet frustrating tasks such as:

These integration challenges burn through IT budget; first, by forcing CTO's to buy expensive observability and APM platforms, and secondly by forcing engineers to spend time on reliability rather than new features. This unfortunate reality often stands in the way of true digital transformation.

Tech and Business Alignment

Beyond the technical challenges posed by building applications in distributed environments—and perhaps because of the distributed nature—, fragmented software architecture leads to a gradual disconnect between what your business needs and what your software does.

In a classic microservice architecture, different teams are in charge of certain microservice bounded contexts, such as user management, order processing, inventory, or loyalty. Many organizations that we have worked with struggle to understand the interactions between these services. For example, one customer says:

We have many different domains, and each team puts out an API that is called by other teams, but we have no way to understand the dependencies between all of those API's. And no one in the company understands our business processes end-to-end.

Besides simply technical challenges, this fragmentation increases the likelihood that software is developed which doesn't actually drive business value because of a lack of clear understanding between product and engineering. This "spaghetti architecture" also prevents opportunities for code reuse and standardization.

Business-as-Code with LittleHorse

Just as Infrastructure-as-Code tools such as Terraform de-fragment infrastructure and make systems more reliable, Business-as-Code delivered through the LittleHorse Kernel allows engineers to have a single source of truth for how their microservices interact.

The central concept of the LittleHorse Kernel is a Workflow Specification, known in code as a WfSpec. A WfSpec is a computational graph defining which computational steps are to be executed, and when.

Here's what a complete order processing workflow looks like in Business-as-Code. This single WfSpec handles the entire business process, from price calculation to credit checks to shipping and it's all in one place, readable by any Java developer. The following code snippet is from one of our examples, showing the definition of a WfSpec that runs the process of handling an order:

    @LHWorkflow(value = "process-order", defaultTaskRetries = "3")
public void wfLogic(WorkflowThread wf) {
// Declare a bunch of variables
email = wf.declareStr("email").asPublic().required().searchable();
item = wf.declareStr("item").asPublic().required();
orderPrice = wf.declareDouble("order-price").asPublic();
status = wf.declareStr("order-status").searchable();
creditScore = wf.declareDouble("credit-score");

status.assign("PROCESSING");

// Calculate Price
orderPrice.assign(wf.execute("fetch-price", item));

// If too big, bring in human approval
wf.doIf(orderPrice.isGreaterThan(10_000.0), this::creditCheck);

status.assign("SHIPPING");
wf.execute("ship-item", email, item);
wf.waitForEvent("item-arrived").registeredAs(Boolean.class);

status.assign("DONE");

wf.execute("send-email", email, "Your Order", "Your order was completed");
}

// You can use lambdas or you can use function pointers to fill out if bodies.
private void creditCheck(WorkflowThread wf) {
creditScore.assign(wf.execute("fetch-credit-score", email));
wf.doIf(creditScore.isLessThan(500.0), ifBody -> {
UserTaskOutput result = ifBody.assignUserTask("verify-credit-check", null, "billing-admins");
ifBody.doIf(ifBody.condition(false, Comparator.EQUALS, result.jsonPath("$.isApproved")), subIfBody -> {
status.assign("REJECTED");
subIfBody.execute("send-email", email, "Your Order", "Your order was rejected due to insufficient credit");
subIfBody.fail("insufficient-credit", "User does not have sufficient credit");
});
});
}

This is the entire business process. No hunting through Slack channels to figure out which service calls which. No wondering if the retry logic is in the queue config or the service code. It's all right here, and it compiles into a visual graph that product managers can actually understand.

A WfSpec is Code

First, you'll notice that the WfSpec is written in Java (as of this publishing, we also have clients in Python, Go, and C# and are evaluating demand for more languages). Although the code uses a DSL provided by the WorkflowThread object, it is compiled and run like any other Java application, and the DSL is readable by any Java programmer.

Secondly, if you look at the DSL you'll see all of the features of a normal programming language. Variables, conditional branching, function calls (TaskRun execution via wf.execute), and more. This DSL code gets compiled down to a metadata object (a WfSpec protobuf, which you can see via lhctl get wfSpec <name>). The actual WfSpec is a computational graph containing Nodes and Edges between the Nodes. Each Node is a computational step to be scheduled by the LittleHorse Server; the Edges determine the control flow. This is much like the abstract syntax tree in normal programming languages.

A WfSpec is Business

Although the WfSpec is code (which comes with a great many set of benefits, such as testing, version control, etc), it is a much higher layer of abstraction than vanilla Java code. The WfSpec shown above spans the entire business process of handling orders. It deals with many different Bounded Contexts and microservices:

  • Shipping (via the ship-item task).
  • Notifications (via the send-email task).
  • External systems (via the fetch-credit-score task).
  • Inventory (via the fetch-price task).
  • Internal company admins (via the verify-credit-check UserTaskRun).

The WfSpec code compiles into a business process, which can be visualized on the LittleHorse Dashboard:

A visualization of the above WfSpec

Life with Business-as-Code

The open-source LittleHorse Kernel gives engineering teams the ability to write end-to-end business processes in code, while abstracting away the non-differentiated tasks such as error handling, retries, and transactional consistency. This yields several benefits to organizations:

  1. Engineering teams no longer lose time and sprints on frustrating tasks related to reliability, debugging, and fault tolerance. This allows engineering teams to work on interesting projects that deliver business value.
  2. The result of work done by engineering teams mirrors the business process more closely, ensuring less "wasted" work and higher alignment between product and engineering.

Get Started!

I am a developer at heart, which is why I wrote the LittleHorse Kernel and open-sourced it. We want software engineers to be able to use familiar and comfortable primitives to operate at a higher level of business value.

To get started: