TT Lab
Get started
Learn Learning paths Courses

Microservice Architecture

Splitting a Monolith Into Two Services

Continue in TT Lab

Goal

Take a monolith in which orders and inventory are in one process, fix the contract first, then separate it into two independent services, and automatically verify that the responses before and after the separation are the same.

Why it matters

The part that is actually hard in separating services is not moving the code. It is checking that the same answer still comes out after moving, and checking that you moved the data ownership along with it. The most common failure in the field is "we split the services but share the tables". In that case deployment became independent, but a schema change still requires agreement between two teams. This is because the coupling was in the data, not the code. So this lab fixes the contract in a file before moving code, and at the end inspects the source to confirm that data access has really been cut. In the Strangler Fig approach, you cannot shift traffic without confidence that the two implementations behind the facade give the same answer.

Steps

  1. Start /opt/fixtures/msa/monolith.py on 127.0.0.1:8101 and make GET /health return 200.
  2. Investigate the monolith's routes and write them to /root/msa/seams.txt, one per line, in the format 경로 도메인 (path and domain). Both domains orders and inventory must appear and there must be at least 4 lines.
  3. Create /root/msa/contract.json. There are two top-level keys, orders and inventory, and each has port (an integer) and paths (an array of strings). orders is 8103 and inventory is 8102.
  4. Create /root/msa/inventory_svc.py and start it on 127.0.0.1:8102. GET /stock/SKU-1 returns {"sku":"SKU-1","qty":<정수>} (qty is an integer).
  5. Create /root/msa/orders_svc.py and start it on 127.0.0.1:8103. POST /orders receives {"sku":"SKU-1","qty":2}, asks the inventory service, and returns 201 and an order_id if there is enough, and 409 if not.
  6. The orders_svc.py source must not contain an inventory data path such as /opt/fixtures/msa/inventory.json, and must instead contain a call to 8102.
  7. Create /root/msa/parity.sh. It sends the same request to the monolith (8101) and the new orders service (8103), and prints PARITY OK if the status code and the verdict are the same. Save the result of running it to /root/msa/parity.out.
  8. In /root/msa/decision.md, include the two headings ## 쪼갠 이유 and ## 쪼개지 말았어야 할 이유 (the reason for splitting and the reason it should not have been split), and write at least 30 characters under each.

Notes

Start the monolith and set a baseline

Start /opt/fixtures/msa/monolith.py on 127.0.0.1:8101 and make GET /health return 200.

If you run /opt/fixtures/msa/monolith.py with python3, it comes up on port 8101. Do not forget to run it in the background (&) and redirect the log.

Make a list of seams

Investigate the monolith's routes and write them to /root/msa/seams.txt, one per line, in the format 경로 도메인 (path and domain). Both domains orders and inventory must appear and there must be at least 4 lines.

Write down the boundary candidates before splitting. Grep the monolith's route definitions and write each path and its responsible domain, one per line.

Fix the contract of the two services

Create /root/msa/contract.json. There are two top-level keys, orders and inventory, and each has port (an integer) and paths (an array of strings). orders is 8103 and inventory is 8102.

The contract comes before the code. Write the service name, port, and exposed paths in JSON. What the inventory service promises is the key.

Separate the inventory service

Create /root/msa/inventory_svc.py and start it on 127.0.0.1:8102. GET /stock/SKU-1 returns {"sku":"SKU-1","qty":<정수>} (qty is an integer).

Move only the inventory-related logic to a new file and start it on 8102. The response must be JSON containing sku and qty.

Separate the orders service

Create /root/msa/orders_svc.py and start it on 127.0.0.1:8103. POST /orders receives {"sku":"SKU-1","qty":2}, asks the inventory service, and returns 201 and an order_id if there is enough, and 409 if not.

The orders service does not read inventory directly but asks over HTTP. Returning 409 when the inventory is insufficient is the contract.

Prove the data ownership is separated

The orders_svc.py source must not contain an inventory data path such as /opt/fixtures/msa/inventory.json, and must instead contain a call to 8102.

If an inventory data file path remains in the orders service source, it is still coupled. Inspect the source.

Compare response parity with the monolith

Create /root/msa/parity.sh. It sends the same request to the monolith (8101) and the new orders service (8103), and prints PARITY OK if the status code and the verdict are the same. Save the result of running it to /root/msa/parity.out.

Write a script that feeds the same input to both paths and compares the results. Have it print PARITY OK if the two responses are the same.

Record the decision to split

In /root/msa/decision.md, include the two headings ## 쪼갠 이유 and ## 쪼개지 말았어야 할 이유 (the reason for splitting and the reason it should not have been split), and write at least 30 characters under each.

Write the grounds for having split and the grounds for not having split. You must write the two specified markdown headings exactly to be graded.