Technical
The Case for Single-File Services
Professional developers are conditioned to split code across many files. It feels organized. It feels like growing up. But for small services I have increasingly chosen the opposite: one file, top to bottom. Four months of this has been eye-opening.
The Claim
For services under 500 lines, a single file is easier to read, faster to change, and simpler to deploy than the multi-module equivalent. The overhead of module structure costs more than it saves until the service grows past a certain threshold.
The Concrete Benefits
Navigation is linear. Find-in-file finds everything. There are no import chains to untangle. There is no 'where does this utility live' question. The whole service fits in your head because it fits on a few screens.
Deployment is trivial. One file goes up. No package structure to manage. No missing init files. For Lambda functions this matches the runtime model perfectly: Lambda already deploys handler files, so a single-file handler is native.
A Real Example
# handler.py - full newsletter subscriber service
import os, json, boto3
from urllib.parse import parse_qs
table = boto3.resource('dynamodb').Table(os.environ['TABLE'])
def validate_email(e):
return '@' in e and len(e) < 320
def handle_subscribe(body):
email = body.get('email', '').strip().lower()
if not validate_email(email):
return {'statusCode': 400, 'body': 'invalid email'}
table.put_item(Item={'email': email})
return {'statusCode': 200, 'body': 'ok'}
def lambda_handler(event, context):
body = json.loads(event.get('body', '{}'))
return handle_subscribe(body)That is a complete production service. Validation, storage, error handling, one file. Splitting it into validation.py, storage.py, and handler.py would add imports, tests per module, and not one bit of real clarity.
When to Split
When the file hits around 500 lines, I start extracting. When testability demands isolation, I extract. When two teams touch the same file, I extract. But the trigger is a specific pain, not a preemptive guess that pain will come.
The Broader Lesson
Architecture is about fitting your code to the problem, not about applying patterns you learned. For a small service, one file is right. For a large system, many files. The skill is reading the actual size of the problem and not overbuilding.
See Gall's Law for the underlying principle: complex systems that work evolved from simple systems that worked. Start simple. Let complexity earn its place.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read