WE NEED 47 MICROSERVICES TO PARSE A JSON (AND OTHER ENTERPRISE LIES)
| **por. Zbigniew | 2 luty 2026 | Poziom cynizmu: BEYOND ENTERPRISE** |
A data-driven takedown of enterprise software complexity
THE PROBLEM
We need to extract a person’s name, email, and phone from a CV.
The CV is in JSON format (JSON Resume), a standard with 50 fields that has been stable since 2014.
Here’s the input:
{
"basics": {
"name": "Jan Kowalski",
"email": "jan@example.com",
"phone": "+48 123 456 789"
}
}
Here’s what we need:
{
"first_name": "Jan",
"last_name": "Kowalski",
"email": "jan@example.com",
"phone": "+48 123 456 789"
}
How hard can this be?
THE ENTERPRISE SOLUTION
Architecture Diagram
+---------------------------------------------------------+
| API Gateway (Kong) |
+----------------------------+----------------------------+
|
+----------------------------v----------------------------+
| cv-ingestion-service |
+----------------------------+----------------------------+
| Kafka
+----------------------------v----------------------------+
| cv-validation-service |
+----------------------------+----------------------------+
| gRPC
+----------------------------v----------------------------+
| basics-parser-service |
| work-parser-service |
| education-parser-service |
| skills-parser-service |
+----------------------------+----------------------------+
| Redis pub/sub
+----------------------------v----------------------------+
| aggregation-service |
+----------------------------+----------------------------+
| RabbitMQ
+----------------------------v----------------------------+
| form-mapping-service |
+----------------------------+----------------------------+
| MongoDB
+----------------------------v----------------------------+
| caching-service (Redis cluster) |
| monitoring-service (Prometheus + Grafana) |
| tracing-service (Jaeger) |
| logging-service (ELK stack) |
+---------------------------------------------------------+
15 services. For one JSON.
The Java Code
@Component
@Primary
@Qualifier("abstractCVProcessorFactoryBeanManagerImpl")
public class AbstractCVProcessorFactoryBeanManagerImpl
implements CVProcessorFactoryBeanManager,
CVProcessorFactoryBeanManagerLifecycle,
CVProcessorFactoryBeanManagerAware {
@Autowired
@Qualifier("cvProcessorStrategyProviderFactoryBean")
private CVProcessorStrategyProviderFactoryBean
cvProcessorStrategyProviderFactoryBean;
// ... 200 more lines ...
}
This is one of 52 Java classes required to parse a name out of JSON.
The Numbers
| Metric | Value |
|---|---|
| Lines of code | 4,200+ |
| Java classes | 52 |
| XML config files | 23 |
| Maven dependencies | 23 |
| Kubernetes YAMLs | 47 |
| Startup time | 12.3 seconds |
| Memory at rest | 256 MB |
| Time to debug “name is null” | 2-4 hours |
THE ABSURDIST COLLECTION
CGI-Perl (1997)
#!/usr/bin/perl
use CGI qw(:standard);
$json = param('cv');
$json =~ /"name"\s*:\s*"([^"]+)"/;
$name = $1;
# No strict, no warnings, no JSON module
# Parse with regex, what could go wrong?
CGI-C (Buffer Overflow Edition)
char buffer[256]; // What's the worst that could happen?
fread(buffer, 1, content_length, stdin); // No bounds checking
char* name = strstr(buffer, "\"name\"");
// Parse JSON by hand with strchr and strstr
This code has 5 exploitable vulnerabilities. It also works 99% of the time.
Node.js Callback Hell (Pre-2015)
parseCV(cv, function(err, parsed) {
if (err) return callback(err);
validateBasics(parsed, function(err, valid) {
if (err) return callback(err);
extractName(valid, function(err, name) {
if (err) return callback(err);
splitName(name, function(err, parts) {
if (err) return callback(err);
// ... 15 more levels ...
});
});
});
});
250 lines of nested callbacks. Zero Promises. Zero async/await.
THE BENCHMARK RESULTS
We benchmarked every solution. Real numbers. Real hardware.
| Solution | LOC | Files | Dependencies | Startup | Memory | Throughput | p99 Latency |
|---|---|---|---|---|---|---|---|
| Python (lean) | 93 | 1 | 0 | 0ms | 12MB | 530,665/s | 0.00ms |
| CGI-C | 89 | 1 | 0 | 5ms | 2MB | 50,000/s | SEGFAULT |
| Node.js Callback Hell | 250 | 1 | 0 | 150ms | 80MB | 5,000/s | 8.00ms |
| CGI-Perl | 45 | 1 | 1 | 50ms | 15MB | 2,000/s | 10.00ms |
| Java Enterprise | 4,200 | 52 | 23 | 12s | 256MB | 850/s | 45.00ms |
| AWS Serverless | 2,100 | 34 | 12 | 800ms | 128MB | 500/s | 800.00ms |
| K8s Microservices | 8,400 | 89 | 156 | 3 min | 2,400MB | 150/s | 1,200.00ms |
The Python script is 3,500x faster than the Kubernetes microservices solution.
It uses 200x less memory.
It has 93 lines vs 8,400 lines.
THE REAL SOLUTION
from dataclasses import dataclass
from typing import Optional
@dataclass
class FormData:
first_name: str
last_name: str
email: str
phone: Optional[str] = None
def parse_cv(cv: dict) -> FormData:
basics = cv.get("basics", {})
name_parts = basics.get("name", "").split(" ", 1)
return FormData(
first_name=name_parts[0] if name_parts else "",
last_name=name_parts[1] if len(name_parts) > 1 else "",
email=basics.get("email", ""),
phone=basics.get("phone"),
)
That’s it. That’s the whole thing.
- Zero dependencies
- 93 lines including tests
- 530,665 CVs/second
- Works in any Python 3.10+ environment
- 100% test coverage
Or if you prefer the shell:
jq '.basics | {
first_name: .name | split(" ")[0],
last_name: .name | split(" ")[1:] | join(" "),
email,
phone
}' cv.json
One line. That’s the entire ATS industry’s core technology.
THE COST ANALYSIS
Processing 1 million CVs per month:
| Solution | Infrastructure | Dev Time | Monthly Cost |
|---|---|---|---|
| Python script | $5 VPS | 2 hours | $5 |
| AWS Lambda | Serverless | 1 week | $50 |
| K8s Microservices | EKS cluster | 3 months | $2,400 |
| Enterprise Java | On-prem servers | 6 months | $15,000 |
The $2.5 billion ATS market is charging enterprise prices for a shell script.
WHY DO COMPANIES DO THIS?
1. Conway’s Law
“Organizations design systems that mirror their communication structure.”
If you have 15 teams, you get 15 microservices.
2. Resume-Driven Development
Engineers want Kubernetes on their resume. Nobody wants “wrote a shell script.”
3. The Complexity Tax
Complexity creates job security. Simple solutions make roles redundant.
4. Vendor Lock-in
Enterprise software vendors sell complexity. Simple solutions don’t require consultants.
5. Cargo Culting
“Netflix uses microservices, so we should too.”
Netflix has 200 million users. You have a JSON file.
THE WORKDAY SPECIAL
Workday, the $64 billion HR software company, processes CVs using:
- Xpresso: A proprietary GUI-based “programming language”
- 47-step wizards to map a single field
- 3-day training required to use basic features
- Documentation behind paywall
Their core technology? The same string splitting you saw in the Python script.
THE DESKTOP APP DISASTER (ELECTRON EDITION)
“We need a native app for better UX.”
So someone decided to build a CV parser as an Electron app. Here’s what that means:
The package.json
{
"dependencies": {
"electron": "^28.0.0",
"react": "^18.2.0",
"redux": "^5.0.0",
"redux-saga": "^1.2.0",
"mobx": "^6.10.0",
"zustand": "^4.4.0",
"axios": "^1.6.0",
"got": "^13.0.0",
"node-fetch": "^3.3.0",
"moment": "^2.29.4",
"date-fns": "^2.30.0",
"left-pad": "^1.3.0",
"is-odd": "^3.0.1",
"is-even": "^1.0.0"
}
}
287 dependencies to parse a JSON file.
Including:
- 5 state management libraries (Redux, MobX, Zustand, Recoil, Jotai) - couldn’t decide
- 9 HTTP client libraries - in case axios breaks
- 4 date libraries - time is hard
- 47 is-* packages -
is-odd,is-even,is-number,is-null… - left-pad - obviously
The Build Pipeline
TypeScript -> Babel -> Webpack -> Rollup -> esbuild -> Parcel -> Vite -> Electron Builder
7 bundlers. For 4 lines of business logic.
The Numbers
| Metric | Electron App | jq one-liner |
|---|---|---|
| Dependencies | 287 | 1 |
| node_modules size | 2.1 GB | 0 |
| Build time | 12 minutes | 0 |
| Final size | 387 MB | 1.2 MB |
| RAM at idle | 1.2 GB | 4 MB |
| Startup time | 8.3 seconds | 2 ms |
| Vulnerabilities | 127 (14 critical) | 0 |
The Vulnerability Report
127 vulnerabilities found
14 critical severity
38 high severity
47 moderate severity
28 low severity
Run `npm audit fix` to fix 23 of them.
104 require manual review.
MS Teams uses this architecture. For a chat app. That uses 1.2 GB of RAM. To send messages.
IRC clients in 1998 used 2 MB.
WHAT SHOULD YOU ACTUALLY USE?
For a Browser Extension
export function parseCV(cv: JSONResume): FormData {
const basics = cv.basics ?? {};
const [firstName = '', ...rest] = (basics.name ?? '').split(' ');
return { firstName, lastName: rest.join(' '), email: basics.email ?? '' };
}
For a Backend Service
def parse_cv(cv: dict) -> FormData:
basics = cv.get("basics", {})
name_parts = basics.get("name", "").split(" ", 1)
return FormData(first_name=name_parts[0], last_name=name_parts[1] or "")
For Bulk Processing
find ./cvs -name "*.json" | parallel jq '.basics | {name, email}' {}
For an API
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
@app.post("/parse")
def parse(cv: dict) -> FormData:
return parse_cv(cv)
Done. Deploy to a $5/month VPS. Handle millions of requests.
THE UNCOMFORTABLE TRUTH
The $2.5 billion ATS market is built on 50 lines of code.
Every “enterprise-grade solution” is just:
json.loads()name.split(" ").get("email")
Everything else is overhead.
Not useful overhead. Not necessary overhead. Just… overhead.
TRY IT YOURSELF
# Install the lean Python package
pip install cv-autofill
# Or use jq
echo '{"basics":{"name":"Jan Kowalski","email":"jan@x.com"}}' | \
jq '.basics | {first: .name | split(" ")[0], last: .name | split(" ")[1], email}'
GitHub: cv-processor-benchmark
All code is MIT licensed. Use it. Mock the enterprise solutions. Build something simple.
“Simplicity is the ultimate sophistication.” - Leonardo da Vinci
“We need 47 microservices.” - Every Enterprise Architect
Disclaimer: This article was written without Kubernetes, without microservices, and without consulting a single enterprise architect. It still works.