The enterprise landscape and capabilities
In short: A capability map describes what the business does regardless of its systems; linked to the applications it shows gaps and duplication, and the TIME model says what to invest in.
Problem
Three systems for invoices and none for returns
The shop has been growing for five years. The shop issues an invoice itself with each order. Accounting buys its own system and issues invoices for companies. Then marketing pays for an invoicing SaaS for the subscriptions, because "it was faster".
The finance director asks why invoices have three numbering schemes. Meanwhile customer service keeps returns in emails and a spreadsheet, and the accountant copies every return by hand.
Every team knows its own system. Nobody sees the whole.
The idea
What the business does, not which systems it has
Enterprise architecture looks at the whole company: all the systems, how they connect and what they are for. It starts not from the systems but from the capabilities: what the business does. It sells, invoices, delivers, takes returns. That changes rarely. Systems, departments and suppliers get replaced, and the shop still invoices ten years later.
A capability map arranges them in groups, usually on one page:
static final List<Group> MAP = List.of( new Group("Sales", List.of("Catalogue", "Cart", "Orders")), new Group("Finance", List.of("Payments", "Invoicing", "Accounting")), new Group("Logistics", List.of("Warehouse", "Delivery", "Returns")), new Group("Customers", List.of("Notifications", "Support")));
static final List<App> APPS = List.of( new App("Shop", List.of("Catalogue", "Cart", "Orders", "Invoicing")), new App("Warehouse 2009", List.of("Warehouse")), new App("Accounting system", List.of("Accounting", "Invoicing")), new App("Invoicing SaaS", List.of("Invoicing")), new App("Payment provider", List.of("Payments")), new App("Courier", List.of("Delivery")), new App("Email service", List.of("Notifications")), new App("Helpdesk", List.of("Support")));record Group(String name, List<String> capabilities) {}
record App(String name, List<String> capabilities) {}Under the map you hang the applications: for each capability, which systems support it. Then two things show up that are otherwise invisible:
- a gap: a capability with no system; people do it by hand;
- duplication: a capability with several systems; you pay several times and have several versions of the truth.
See it
The map, coloured by coverage
// the systems that support the capabilitystatic List<String> appsFor(String cap, List<App> apps) { List<String> names = new ArrayList<>(); for (App app : apps) if (app.capabilities().contains(cap)) names.add(app.name()); return names;}
static String coverage(List<String> names) { if (names.isEmpty()) return "✗ no system"; if (names.size() > 1) return "⚠ " + names.size() + " systems: " + String.join(", ", names); return names.get(0);}Step by step, in words
- The capability map: what the business does, in groups. No systems on it yet.
- The 8 applications come one by one. Each says which capabilities it supports, and their counts grow.
- A capability with exactly one system is covered: green.
- Invoicing: 3 systems do it. Three licences, three sets of invoice numbers, three places to fix.
- Returns: no system at all. People keep them in emails and spreadsheets.
- The map coloured by coverage: 1 gap and 1 duplication. The target state starts from here.
// the systems that support the capabilitystatic List<String> appsFor(String cap, List<App> apps) { List<String> names = new ArrayList<>(); for (App app : apps) if (app.capabilities().contains(cap)) names.add(app.name()); return names;}
static String coverage(List<String> names) { if (names.isEmpty()) return "✗ no system"; if (names.size() > 1) return "⚠ " + names.size() + " systems: " + String.join(", ", names); return names.get(0);}
static void printMap(List<Group> map, List<App> apps) { int gaps = 0, duplicated = 0; for (Group group : map) { System.out.println(group.name()); for (String capability : group.capabilities()) { List<String> names = appsFor(capability, apps); if (names.isEmpty()) gaps++; if (names.size() > 1) duplicated++; System.out.println(" " + capability + ": " + coverage(names)); } } System.out.println("Gaps: " + gaps + ", duplicated: " + duplicated);}printMap(MAP, APPS);Sales Catalogue: Shop Cart: Shop Orders: ShopFinance Payments: Payment provider Invoicing: ⚠ 3 systems: Shop, Accounting system, Invoicing SaaS Accounting: Accounting systemLogistics Warehouse: Warehouse 2009 Delivery: Courier Returns: ✗ no systemCustomers Notifications: Email service Support: HelpdeskGaps: 1, duplicated: 1List.of keeps the order, and a record gives a constructor and accessors for the fields without a single extra line.The program is small, but the real work is in the data: what counts as a separate capability, and what each system really does. You gather that by talking to the teams, not with code.
Try it
Fill in
How do you check that the application supports the capability?
for (App app : apps)
if (app.capabilities().(cap))
names.add(app.name());The check is whether the capability is in the application's list. The list is small, so a linear search is perfectly enough.
The idea
Application portfolio: TIME
The map says where the problem is. The application portfolio says what to do with each system. For each one you record what it costs per year and two scores from 1 to 5:
- business value: how much the business needs it;
- technical condition: how healthy it is inside (is it maintained, are there people who know it, how often does it go down).
The two scores give four decisions, known as the TIME model (Gartner):
| technically healthy | technically sick | |
|---|---|---|
| valuable to the business | Invest | Migrate |
| of little value | Tolerate | Eliminate |
record Rating(String app, int costPerYear, int business, int technical) {}// TIME: is it worth much to the business, and is it healthy insidestatic String decide(Rating r) { boolean valuable = r.business() >= 3; boolean healthy = r.technical() >= 3; if (valuable && healthy) return "invest"; if (valuable) return "migrate"; if (healthy) return "tolerate"; return "eliminate";}The prices below are examples, and the scores are the team's.
List<Rating> ratings = List.of( new Rating("Shop", 60000, 5, 3), new Rating("Warehouse 2009", 18000, 4, 1), new Rating("Accounting system", 24000, 4, 4), new Rating("Invoicing SaaS", 9600, 2, 2), new Rating("Helpdesk", 4800, 2, 4));int total = 0, saved = 0;for (Rating r : ratings) { String decision = decide(r); System.out.println(r.app() + ": " + decision + " (business " + r.business() + ", technical " + r.technical() + ")"); total += r.costPerYear(); if (decision.equals("eliminate")) saved += r.costPerYear();}System.out.println("Per year: " + total + " €, you drop " + saved + " €");Shop: invest (business 5, technical 3)Warehouse 2009: migrate (business 4, technical 1)Accounting system: invest (business 4, technical 4)Invoicing SaaS: eliminate (business 2, technical 2)Helpdesk: tolerate (business 2, technical 4)Per year: 116400 €, you drop 9600 €TIME is not a verdict but the start of a conversation. "Tolerate" means "do not spend on it", not "forget it": the Helpdesk works and is not in the way. "Eliminate" needs a date and a plan, or the application lives for five more years.
Try it
Predict the output
The mobile app brings half of the orders (business 4), but it is written on a framework that is no longer maintained (technical 2). What does decide say?
System.out.println(decide(new Rating("Mobile app", 30000, 4, 2)));Valuable (4 ≥ 3) but sick (2 < 3): migrate. The business needs the function, not the system.
Try it
Find the bug
A colleague wrote decide with copy and paste. Now the portfolio says:
Shop: invest (business 5, technical 3)Warehouse 2009: invest (business 4, technical 1)Accounting system: invest (business 4, technical 4)Invoicing SaaS: eliminate (business 2, technical 2)Helpdesk: eliminate (business 2, technical 4)Per year: 116400 €, you drop 14400 €Warehouse 2009 is suddenly up for investment and the Helpdesk is to be eliminated. Which line is the bug on?
Pick the line with the bug.
healthy reads the business score instead of the technical one: the line was copied from the one above and not changed. So Warehouse 2009 (business 4) looks healthy and the Helpdesk (business 2) looks sick. Two scores that look alike are easy to mix up: a test with an application whose two scores differ catches the bug at once.
The idea
Target state and roadmap
The map and the portfolio give the target state: what the landscape should look like in a year or two. For the shop:
- invoicing is only in the accounting system, with one numbering scheme; the invoicing SaaS goes (eliminate), and the invoice module in the shop is switched off;
- the warehouse is replaced (migrate) with a new one that also supports returns: the gap is filled where the goods are;
- everything else stays.
The roadmap is the order of steps to get there, with intermediate states that work:
- the new warehouse takes over returns, and the old one stays for the goods; the link to Warehouse 2009 goes through an anti-corruption layer, so its CSV does not leak into the new code;
- the goods move to the new warehouse gradually, as in "Changing a live system", until Warehouse 2009 has no traffic left;
- the shop's invoices move to the accounting system; the numbering changes from the new year, so it is clear for the accountants;
- the SaaS subscription is cancelled after the last invoice in it.
Each step is a separate decision with an ADR, its own cost and its own risks in the register. The order is chosen by pain and by dependencies: returns come first, because money is lost there today.
More precisely, if you are curious
The frameworks. TOGAF is the best known enterprise architecture framework: it describes a method (ADM) for these steps and many documents. ArchiMate is a language for diagrams of the landscape, and Zachman is a table for classifying the descriptions. Here we only name them: the course teaches the work, and certification is a separate path.
Capability, process and department. A capability is the "what" (invoicing). A process is the "how", in steps (order → invoice → payment). A department is the "who". The map is made of capabilities because they change the least.
The tools. Large companies keep the portfolio in dedicated EA tools or in a CMDB. A small company keeps it in a spreadsheet. What matters is that it is one place and it is kept up to date.
The idea
When it helps and when it is bureaucracy
Enterprise architecture helps when:
- the systems number in the dozens and nobody keeps them all in their head;
- the company merges with another and must decide which system stays;
- software spending grows and nobody knows what it pays for;
- a regulator asks where the customer data is.
It does harm when:
- the map is the goal. Drawn, printed and forgotten. A map that no decision was ever made with is decoration.
- a board approves every library. Decisions that one team can reverse by itself stay with the team. Only what is expensive for the whole company is decided centrally: shared identity, payments, customer data.
- the company is small. Three systems and one team do not need a framework: a one-page table and ADRs are enough.
- the framework replaces the conversation. The documents of the framework are not the work. The work is the decision that comes out of them.
Exercise
The target state
Solve this one in your editor.
Write the target state as a new list of applications: the shop no longer invoices, the invoicing SaaS is gone, and Warehouse 2009 is replaced by "New warehouse", which supports the warehouse and returns. Run the same coverage check on it:
Sales Catalogue: Shop Cart: Shop Orders: ShopFinance Payments: Payment provider Invoicing: Accounting system Accounting: Accounting systemLogistics Warehouse: New warehouse Delivery: Courier Returns: New warehouseCustomers Notifications: Email service Support: HelpdeskGaps: 0, duplicated: 0More exercises
- A fitness function for the landscape. Turn the check into a test that fails if there is a gap or a duplication without a recorded decision (a list of allowed duplications and their reasons).
- The cost of duplication. Add each application's cost and print how much all the systems of the duplicated capabilities cost per year.
- Two countries. The shop launches in Greece with a local courier. Are two delivery systems a violation? How do you show it on the map?
Test
Check yourself
Related lessons
Section titled "Related lessons"- Builds on: Non-functional requirements you can measure · Integrating old and foreign systems · Changing a live system (strangler fig, expand–contract) · Architecture review
- Continues in: Your first architecture task
- Tasks on this topic: The architect at work