In this blog series, I’ll guide you through the process from “I have a cool idea for a Blockchain scenario” to “This is the business value of that idea” leveraging the quote from Abraham Lincoln.
Before we start the process, let’s define the tools and the terms we want to use.
Solution Space versus Problem Space
The solution space in the quote above is the chopped tree, while the problem space is harder to define. Reading the quote tells us that we can use 75% of our time for the problem space and 25% for the solution space. When we spend our time on the problems we will find issues like:
- The tree if difficult to hit
- The axe is blunt
- It is to dark outside
- … (here you can add your ideas)
In our day-to-day business world, we would focus on chopping the tree, even if the axe is blunt. Someone tells us to cut the tree – so we work on that task instead of investing our precious time on the Problem Space.
While reading this blog, please try to stay in the Problem Space – instead of immediately jumping to the Solution Space – even though you think that you already know the solution.
How to stay in the Problem Space
By definition! We define that we stay in the problem space, until the business case is clear. All implementations that we do, all iterations when incorporating customer and stakeholder feedback are used to draw a clear picture in the Problem Space.
After we found the Business Case that works fine in an elevator pitch, we can implement the first version of our Blockchain Solution in the Solution Space.
Domain Driven Design Principles
The one rule of “Domain Driven Design” that is relevant for this blog is the “Common language for all stakeholders”. Instead of the Business Analysts learning the Developer language or the developers learning the business analyst language, both have to learn a new language – The Domain Language.
There are different ways to define the Domain Language, but you should always stick to the “iterative; fail early/fail often” approach.
Test Driven Development Principles
For this blog, Tests First“ is the most important principle that we use from the Test Driven Development . Without a test, you are not allowed to write the code. As a developer this is hard to achieve.
Stakeholder Feedback
As we already stated, our approach is “iterative; fail early/fail often”.
Let’s do a little Scrum digression. You are a developer showing your results of the last sprint and everybody (should be all stakeholders) says “great work”. Of course this is a nice compliment but you get paid for the work and you should know what you did.
Wouldn’t it be nice, if you get questions like “Why did you do it like that?” or “Oh, that’s not exactly what we meant when we talked about the solution”. It’s about “fail early, fail often” which will lead us to happy customers and great business value of our solution.
Stakeholders want to know the benefits that they gain when using the solution. The way how the solution was build is Priority 2. In our approach, we start with the assumption: “Let’s assume that the solution is done”. We focus on the solution usage.
The approach: Working in the Problem Space
The approach which we are using to work in the problem space is based on Test Driven Development. We will start with a first question and create a test for that questions.
We run the test and work on the coding until the test is green. While trying to make the test green, new questions will show up. We will continue this iterative approach, until the test is green.
For this blog, we will use JAVA with Spring Boot and unit testing. The „Run Test“ is the one feature that helps us to stay in the Problem Space. It guides us through our work.
Of course, you could use any other programming language that provides a similar testing framework.
The Blockchain Scenario
In this section we will work on one blockchain scenario to illustrate the approach. It will not be a complete prototype implementation but it will cover all relevant aspects of our approach.
The Solution Idea
NFTs could be used as authenticity certificate. Someone buys expensive limited sneakers. Instead of getting a printed “Certificate of Authenticity”, she will get an NFT which was created for that limited sneakers.
To set the stage for analyzing the Problem Space, we will define a set of assumptions. Assumptions are an efficient way to reduce complexity. As we are using an iterative approach, we can update the assumptions with each iteration. Our focus is on the completeness of the end to end business process, instead of the depth of business process.
First Assumptions:
- SAP S/4 HANA system should be used
- The shipment of sneakers and payment is not covered
- A Web Shop is available for the ordering of sneakers
- Events are used to integrate the Web Shop and the SAP S/4 HANA System
- The customer buying the sneakers knows how to handle NFTs
The picture below shows a simplified ordering process. The three lanes represent the Web Shop, where the customer can order the sneakers, the Blockchain part and the SAP S/4 HANA system.
We will now use the Test Driven Development approach and create a new Spring Boot project in JAVA. As a starting point, we define question that should be covered by the tests.
Define the questions we would like to answer by the test
- How is the integration of SAP S/4 HANA and Blockchain done?
- What is the business value for SAP?
- What is the business value for the Customer?
Question 1: How is the integration of SAP S/4 HANA and Blockchain done?
The starting point is to create a test for the scenario. In the test, we separate the assumptions (see assumeTrue…) and the checks for the process.
@Test
void e2e() {
BuyingSneakersScenario cut = new BuyingSneakersScenario();
assumeTrue(cut.nftCollectionIsAvailable());
assumeTrue(cut.productIsCreatedInS4());
assumeTrue(cut.relationOfProductAndNftIsSetup());
OrderId orderId = cut.customerOrdersProduct();
assertTrue(cut.customerChecksRecentOrders(orderId));
assertTrue(cut.customerOwnsNft(orderId));
assertTrue(cut.manufacturerSeesNftMintingTransaction(orderId));
}
First Problem in the Problem Space: How to make the test green?
We follow the guidelines of test driven development to minimize the coding and just write enough code to make the tests green.
The coding below shows the first approach to make the tests green.
/**
* Sneaker scenario
*/
public class BuyingSneakersScenario {
private final S4System s4System;
private final WebShop webShop;
private final Blockchain blockchain;
public BuyingSneakersScenario(WebShop webShop, Blockchain blockchain
,S4System s4System) {
this.webShop = webShop;
this.blockchain = blockchain;
this.s4System = s4System;
}
public boolean nftCollectionIsAvailable() {
return blockchain.nftCollectionIsAvailable();
}
public boolean productIsCreatedInS4() {
return s4System.productIsCreated();
}
public boolean relationOfProductAndNftIsSetup() {
//ToDo: How is the relation done?
}
It was easy to write the code until the relationOfProductAndNftIsSetup() method needs to be implemented.
Second Problem: How is the relation of SAP S/4 HANA and Blockchain done?
There needs to be something that takes care for the relation of a product in SAP S/4 HANA and the NFT in Blockchain, let’s call it S4NftRelationService.
@Service
public class S4NftRelationService {
}
And the constructor of our scenario looks like that:
public BuyingSneakersScenario(WebShop webShop, Blockchain blockchain
,S4System s4System, S4NftRelationService relationService) {
this.webShop = webShop;
this.blockchain = blockchain;
this.s4System = s4System;
this.relationService = relationService;
}
It was easy to write the coding for relationOfProductAndNftIsSetup() method as we delegate the task to our relation service. Now we got stuck at the customerOrdersProduct() method.
public BuyingSneakersScenario(WebShop webShop, Blockchain blockchain
, S4System s4System, S4NftRelationService relationService) {
this.webShop = webShop;
this.blockchain = blockchain;
this.s4System = s4System;
this.relationService = relationService;
}
public boolean nftCollectionIsAvailable() {
return blockchain.nftCollectionIsAvailable();
}
public boolean productIsCreatedInS4() {
return s4System.productIsCreated();
}
public boolean relationOfProductAndNftIsSetup() {
return relationService.relationOfProductAndNftIsSetup();
}
public OrderId customerOrdersProduct() {
//ToDo: What is customer?
}
Third Problem: What is “customer”?
You know the solution already – we just create a component customer
@Component
public class Customer {
}
and add the customer to the constructor of our scenario.
public BuyingSneakersScenario(WebShop webShop, Blockchain blockchain
, S4System s4System, S4NftRelationService relationService
, Customer customer) {
this.webShop = webShop;
this.blockchain = blockchain;
this.s4System = s4System;
this.relationService = relationService;
this.customer = customer;
}
The advantage of the test driven approach is cutting the big problem into small problems. You can even delegate the problems to different developers. Someone needs to take care for the Customer, someone for the the separation of the S4NftRelationService, etc.
Another advantage is the coverage of the integration aspects. Integration is there from the beginning and everything is always integrated.
The coding below shows the next approach to make the tests green.
public BuyingSneakersScenario(WebShop webShop, Blockchain blockchain
, S4System s4System, S4NftRelationService relationService
, Customer customer) {
this.webShop = webShop;
this.blockchain = blockchain;
this.s4System = s4System;
this.relationService = relationService;
this.customer = customer;
}
public boolean nftCollectionIsAvailable() {
return blockchain.nftCollectionIsAvailable();
}
public boolean productIsCreatedInS4() {
return s4System.productIsCreated();
}
public boolean relationOfProductAndNftIsSetup() {
return relationService.relationOfProductAndNftIsSetup();
}
public OrderId customerOrdersProduct() {
return webShop.orderProduct(customer);
}
public boolean customerChecksRecentOrders(OrderId orderId) {
return webShop.customerChecksRecentOrders(orderId);
}
public boolean customerOwnsNft(OrderId orderId) {
//ToDo: What is the relation between customer, orderId and NFT?
}
The parts with the Customer are implemented using the WebShop component and the Customer component, but the next question comes up:
Forth Problem: What is the relation between customer, order Id and NFT?
In order to solve this problem, let’s do some new assumptions that simplify the solution without removing the interesting aspects.
First let’s take a closer look at the Blockchain component. Here are the new assumptions:
Blockchain Component assumptions:
- There are transactions in the Blockchain with transaction ids
- Ordering sneakers in the Web Shop creates one transaction for the NFT
- The “users” of the Blockchain are identified by their Blockchain Address
- The customer knows his Blockchain Address
S4NftRelationService assumptions:
- Knows the relation of product and NFT
- Knows the relation of order id and product
With these assumptions, we can implement the customerOwnsNft() method.
While trying to implement the manufacturerViewsNftMintingTransaction() method, we realized, that we did not define the manufacturer. We add the Maufacturer component to the constructor of our scenario. The code below shows the complete scenario implementation.
public BuyingSneakersScenario(WebShop webShop, Blockchain blockchain
, S4System s4System, S4NftRelationService relationService
, Customer customer, Manufacturer manufacturer) {
this.webShop = webShop;
this.blockchain = blockchain;
this.s4System = s4System;
this.relationService = relationService;
this.customer = customer;
this.manufacturer = manufacturer;
}
public boolean nftCollectionIsAvailable() {
return blockchain.nftCollectionIsAvailable();
}
public boolean productIsCreatedInS4() {
return s4System.productIsCreated();
}
public boolean relationOfProductAndNftIsSetup() {
return relationService.relationOfProductAndNftIsSetup();
}
public OrderId customerOrdersProduct() {
return webShop.orderProduct(customer);
}
public boolean customerChecksRecentOrders(OrderId orderId) {
return webShop.customerChecksRecentOrders(orderId);
}
public boolean customerOwnsNft(OrderId orderId) {
BlockchainAddress customerAddress = customer.getBlockchainAddress();
Product product = s4System.getProduct();
Nft nft = relationService.getNft(product, orderId);
return blockchain.addressOwnsNft(customerAddress, nft);
}
public boolean manufacturerViewsNftMintingTransaction(OrderId orderId) {
TransactionId transactionId = relationService.getTransactionId(orderId);
return s4System.viewNftMintingTransaction(manufacturer, transactionId);
}
The next steps are the implementation of the new components and services that we defined. We can always click on “Run Test” and see, if we need to do more work to reach the goal of a green test.
The final test is shown below. Spring Boot takes care for all initialization of Components and Services. Run this test to check if everything is green.
@SpringBootTest
class BuyingSneakersScenarioTest {
@Autowired
BuyingSneakersScenario cut;
@Test
void e2e() {
assumeTrue(cut.nftCollectionIsAvailable());
assumeTrue(cut.productIsCreatedInS4());
assumeTrue(cut.relationOfProductAndNftIsSetup());
OrderId orderId = cut.customerOrdersProduct();
assertTrue(cut.customerChecksRecentOrders(orderId));
assertTrue(cut.customerOwnsNft(orderId));
assertTrue(cut.manufacturerViewsNftMintingTransaction(orderId));
}
}
The Domain Language
To reach the green test, we created several classes. Each of them should be added to the Domain Model with a glossary entry. We use JAVADOC to describe them. Here is a screen shot of a simple JAVA documentation of all classes.
Visualizing the scenario flow
During the implementation of the tests, components and services are created on the fly. In order to visualize the flow and interaction of these components and services, we leverage the logging framework.
We will start to add loggers to the scenario, components and services. When running the scenario tests, the logs will visualize the flow:
For example here is the Blockchain component with its loggers:
@Component
public class Blockchain {
private static final Logger log = LoggerFactory.getLogger(Blockchain.class);
public boolean nftCollectionIsAvailable() {
log.info("check if the nft collection is available");
return true;
}
public boolean addressOwnsNft(BlockchainAddress address, Nft nft) {
log.info(String.format("check if %s owns %s", address, nft));
return true;
}
}
Then we can use the “Run Test” capability of our unit testing framework. It will show the logging of all components and services.
Step | Component/Service | Action |
1 | BuyingSneakersScenarioTest | check if the assumptions are fulfilled |
2 | Blockchain | check if the nft collection is available |
3 | S4System | check if the product was created |
4 | S4NftRelationService | check if the relation of product and Nft is setup |
5 | BuyingSneakersScenarioTest | execute one buying process |
6 | WebShop | order product for Customer |
7 | WebShop | customer checks if recent orders contain order OrderId[id=4711] |
8 | Customer | provide the Blockchain address |
9 | S4System | provide the product |
10 | S4NftRelationService | provide the nft of Product{id=’0815′} for OrderId[id=4711] |
11 | Blockchain | check if BlockchainAddress[address=4711] owns nft |
12 | S4NftRelationService | provide transaction id |
13 | S4System | check if Minting Transaction is available |
Question 2: What is the business value for SAP?
In a following blog, we will take a look at this business related question. We will use the same test driven approach to examine the problem space.
A test could look like this:
class BusinessCaseTest {
private static final int TARGET_IN_MIO_EURO = 10;
@Test
void e2e() {
BusinessCase cut = new BusinessCase();
int earningsBefore = cut.getSAPEarnings();
cut.customersSubscribeSolution();
assertTrue(cut.getSAPEarnings()>=earningsBefore+TARGET_IN_MIO_EURO);
}
}