Send request

No products in the cart.

Developing Microservices with Behavior Driven Development and Interface Oriented Design –

January 30, 2024

A monthly overview of things you need to know as an architect or aspiring architects.
View an example

We protect your privacy.
Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Josh Grossman provides a brief overview of what the ASVS is, but takes a closer look at balancing trade-offs and prioritizing different security requirements. Josh shares how to make the process repeatable and how to implement it as part of your own organization’s requirements process.
Erica Pisani discusses what the edge is, how running code and serving data on the edge can improve site performance, and how to leverage these options to maximize site performance.
In this podcast, Sam shares his insights on Redis’ vector database offering, different approaches to embeddings, how to enhance large language models by adding a search component for retrieval augmented generation, and the use of hybrid search in Redis.
Charity Majors discusses how platform engineering teams are different from other engineering teams, and presents some of the ways they run into traps and other troubles.
In this article, we will discuss what problems we had to solve at Twilio to efficiently build a resilient and scalable asynchronous system to handle a complex workflow and the advantages we got from adopting a Workflow Orchestration solution, including abstracting away state management and out-of-the-box support for retries, observability, and audibility.
Discover new ideas and insights from senior practitioners driving change in software. Attend in-person.
Discover transformative insights to level up your software development decisions. Register now with early bird tickets.
Level up your software skills by uncovering the emerging trends you should focus on. Register now.
Your monthly guide to all the topics, technologies and techniques that every professional needs to know about. Subscribe for free.
InfoQ Homepage Articles Developing Microservices with Behavior Driven Development and Interface Oriented Design
Leia em Português
Jan 26, 2019 9 min read
Kenneth Pugh
reviewed by
Shane Hastie
Microservices are relied upon by other microservices and by entire applications.  This dependence requires services that are well defined and well tested.  These goals can be achieved with behaviors and interface contracts specified by tests.  With Behavior Driven Development (BDD), a service’s functionality is described by tests that concentrate on the operations to be performed rather than the syntax of these operations such as JSON or XML.    Automating these tests typically requires test doubles for other microservices whose behavior is specified by their own BDD tests.  Interface Oriented Design (IOD) includes other contractual obligations of a microservice, such as limitations on resource usage, throughput, and error reporting.    Together BDD and IOD help describe a service’s behavior so that consumers can easily understand and rely upon it.       
BDD involves the triad – the three perspectives of the customer, of the developer, and of the tester.  It’s usually applied for the external behavior of an application.   Since microservices are internal, the customer perspective is that of the internal consumer, that is, the parts of the implementation (e.g. other microservices) which uses the service.   So the triad collaboration is between the consumer developers, the microservice developers, and the testers.   
Behavior is often expressed in a Given-When-Then form, e.g.  Given a particular state, When an action or event occurs, Then the state changes and/or an output occurs.  Stateless behavior, as business rules and calculations, just shows the transformation from input to output.  
Interface Oriented Design focuses on the Design Patterns principle “Design to interfaces, not implementations”.   A consumer entity should be written against the interface that a producer microservice exposes, not to its internal implementation.    These interfaces should be well defined, including how they respond if they are unable to perform their responsibilities.   Domain Driven Design (DDD) can help define the terms involved in the behavior and the interface.  
Microservices can either be synchronous where a consumer calls another producer microservice directly and awaits the result or asynchronous where the service responds to a message that the consumer has placed on a queue.   This article’s examples will be on synchronous services.  
A service provides a cohesive set of related operations.   This example in an ordering application is a service that computes the discount for a customer placing an order.   

An outline of the behavior of this service could be:
The service may compute the result using an implementation in code, a local database, or contacting other services.   We’ll take a look at that later.    
The service may use JSON or XML as the underlying communication protocol.    However, specifying the behavior of the service in an implementation independent way helps to separate the operations from the syntax.   
With BDD, one can start with sample data to get an understanding of the desired behavior.  The triad may come up with:   
The first two columns are the input to the service and the column on the right is the output from the service. 

The sample identifies domain terms which might need further descriptions of their behavior, such as allowable values.   The triad could agree upon the following terms.   The implied contract for the service is that it should return the proper value if the inputs fall within these allowable values.  
Behavior, particularly with microservices, often include responses that indicate failure to perform the operation.  Defining the potential failures helps the consumer determine what it needs to handle.   Consumers may use standard libraries (e.g. Netflix’s Hystrix) to deal with some of these failures.   Some potential failures might be:  
Failures may be expressed as numeric values or symbolic values in the communication protocol.   Using meaningful names in the BDD helps to emphasize the semantics of the failure, rather than the failure syntax.    For example, If the value passed as the category does not appear on the list of valid values, then the service would return a failure indicator that corresponds to “Parameter value invalid”.     This might be represented in the underlying service by a “400 – Bad Request” return with a payload of “Parameter value invalid”. 
Alternatively, one could define a default value to return (e.g. 0) if any of the parameters were invalid.  The service should have the responsibility to log this issue, so that its ramifications can be analyzed.   
BDD service tests can form a context for the unit tests of entities (e.g. classes) that comprise the service.   Through the design process, responsibilities for passing the BDD tests are assigned to the classes and methods.   The unit tests specify these responsibilities.   
A consumer of a service often requires a test double for services it calls.  In particular, services that are slow, expensive, or random need test doubles.  If the behavior of the discount service never changed, then the production discount service might be used in testing the consumer.   However, changes are inevitable, so that a test double is typically required.  

The test double could be one that always returns the same values, e.g. 
The consumer’s tests could rely on these values.  In this example, constant behavior might be sufficient.   However, for other tests, it may be preferable that the test sets up the response of the test double.   
The consumer test would set up the discount test double to respond with the given value when the input is presented.   For example:    
Alternatively, the discount test double could simply respond with the amount, regardless of what input was presented to it.  
Let’s see how this test double might fit into a larger scenario.  Here’s the behavior for an order that includes both a discount and a tax.   The tax is computed by a microservice that is similar to the discount.   

Given a customer: 
And discount is setup as:
And tax is setup as: 
When the customer places an order with: 
Then the amounts on order are: 
If the discount service relied on a local database for information on how to compute the discount, then the database contents represents a state of the service.  How the service’s state changes in response to updates to the data should be documented.   For example, suppose the service relied on the following data:  
There will be some other aspect of the service that permits the update of this data.  The update could be arranged so that individual elements are updateable or that the entire table is updated at once. Here’s an example of a behavioral test for individual update:  
Given the current data:  
When an element is updated:
Then the updated data is: 
One could also check that the updated data is used to compute the discount: 
The discount service could have a local persistent storage mechanism to save the data in the previous example.   However, it could depend on another persistency service to maintain this data. If that were the case, the tests in the previous section would be applied to that service.   Every dependency can bring up another issue. What should be the behavior of a service if its dependencies are unavailable?   For the discount service, should it indicate a failure or just return a default value?   Sometimes a global failure policy can provide the answers, but often the decision relies on the context of the service.    
Once the behavior for a microservice has been agreed upon, it can be formulated into automatable tests.   There are several microservice testing frameworks such as PACT or Karate.  Alternatively, you can use BDD frameworks such as Cucumber or FIT.   The test implementation, e.g. the Cucumber step definitions, uses microservice libraries to execute the request/response.   Additional environmental information can be provided as part of the scenario or as background.  For example, a Cucumber feature file could include the following.  There could be several variations, depending on your testing conventions.    
The values in the first two columns could be transferred into whatever is your calling convention, such as into query parameters. The result in the body should match the third column.   If the query names and values are the column names and values, this decreases the impedance between the test and the implementation 
For reusability, step definitions could be written for any service that computes a calculation or determines a business rule result so that a common parsing library could be used.  In the example above, a convention such as the “?” (as in Discount Amount above) helps distinguish for the parser what is input and what is output.      
The tests should also include tests for failure modes, such as:
Designing microservices with BDD concentrates on the semantics of the operations and not the underlying syntax of the implementation.   Following the IOD guideline that services are responsible for performing their operation and notifying someone (consumers or a logger) of issues, helps to delineate the responsibilities for reaction to failures.  Having well defined services makes it much easier to make them work together to provide the desired external behavior.   
Ken Pugh helps companies evolve into lean-agile technical organizations through training and coaching. His special interests are in creating high quality systems with Acceptance Test-Driven Development / Behavior Driven Development, accelerating DevOps by collaboration,  and using lean principles to deliver business value quickly.  He has written several software development books including the 2006 Jolt Award winner Prefactoring and his latest: Lean-Agile Acceptance Test-Driven Development: Better Software Through Collaboration. Ken has helped clients from London to Boston to Sydney to Beijing to Hyderabad. He is the co-creator of the SAFe® Agile Software Engineering course. You can see all his services and contact him at  

A round-up of last week’s content on InfoQ sent out every Tuesday. Join a community of over 250,000 senior developers. View an example

We protect your privacy.
You need to Register an InfoQ account or or login to post comments. But there’s so much more behind being registered.
Get the most out of the InfoQ experience.
Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p
by Piotr Żarek,
by Piotr Żarek,
Your message is awaiting moderation. Thank you for participating in the discussion.

Very interesting article, thank you! I’m confused in one point though. At the beginning of the article you’re mentioning that

Which suggests that the details of the infrastructure layer should be out of scope for the gherkin scenario. At the same time at the end you’re suggesting the following form:

Which seems to include a lot of low level details like the structure of the URL (the actual base URL, GET method, path etc). I’m a bit lost. I’d be very grateful for clarification. Thank you!

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

A round-up of last week’s content on InfoQ sent out every Tuesday. Join a community of over 250,000 senior developers. View an example

We protect your privacy.
April 8-10, 2024
Real-world technical talks. No product pitches.
Practical ideas to inspire you and your team.
QCon London International Software Development Conference returns on April 8-10, 2024. Level-up on 15 major software and leadership topics including; The Tech of FinTech, What’s Next in GenAI and Large Language Models (LLMs), Performance Engineering, Architecture for the Age of AI, Innovations in Data Engineering and more.
Learn the emerging trends. Explore the use cases. Implement the best practices.
SAVE YOUR SPOT NOW and all content copyright © 2006-2023 C4Media Inc.
Privacy Notice, Terms And Conditions, Cookie Policy


Posted in Design, Events, Technology, Ui DesignTags:
Write a comment