Evolving Solutions for Growing Systems

This document examines how solutions must evolve as systems grow from simple scripts to complex distributed applications. It demonstrates technology progression through a Secret Santa example, starting with CSV files, advancing through SQLite and database servers, adding caching layers, and ultimately scaling to cloud-based distributed architectures with load balancing.

This document illustrates how technical solutions must evolve alongside system growth and complexity. Through a Secret Santa application example, it traces the progression from simple CSV file storage through SQLite databases, dedicated database servers, caching layers, distributed web services, and cloud infrastructure, demonstrating the principle of choosing appropriately scaled solutions for each stage of growth.


The Context-Dependent Nature of Solutions

Solutions Are Not Universal

A solution that’s good for one problem might not be well-suited for a different problem. And as a system becomes more complex and grows in usage, a solution that worked well before may no longer be appropriate.

Solution effectiveness factors:

FactorImpact on Solution ChoiceExample
Scale of usageDetermines infrastructure needs10 users vs 10 million users
Data volumeAffects storage technology100 records vs 100 million records
Complexity of featuresInfluences architectureSimple email vs ML recommendations
Performance requirementsDictates optimization levelSeconds acceptable vs milliseconds required
Budget constraintsLimits available optionsFree tools vs enterprise solutions

Case Study: The Evolving Secret Santa Application

The Initial Problem

Consider writing a Secret Santa script where each person gives a secret gift to one other randomly assigned person. The script randomly selects pairs of people and then sends an email to the gift-giver telling them who they are buying a present for.

Initial requirements:

RequirementSpecification
ScopePeople working on one floor
DataNames and email addresses
FunctionalityRandom pairing + email notification
UsersSmall, defined group
FrequencyOnce per year

Stage 1: CSV File Storage

The Simple Approach

If this is being done for the people working on a floor, the list of names and emails might be stored in a CSV file.

CSV file approach:

AspectCharacteristicSuitability
Data sizeSmall (dozens of entries)Excellent
Parsing timeNegligibleNo performance issue
Setup complexityMinimalIdeal for quick implementation
MaintenanceEasy manual editingAppropriate for small scale
Access controlFile system permissionsSufficient for single-user script

Example CSV structure:

1name,email
2Alice Smith,alice@company.com
3Bob Johnson,bob@company.com
4Carol Williams,carol@company.com

The file will be small enough that the time spent parsing it won’t be significant.

When CSV Files Work Well

ScenarioWhy CSV Is Appropriate
Small datasets (<1,000 records)Fast to parse, easy to manage
Infrequent accessNo need for query optimization
Single user or simple access patternsNo concurrency issues
Simple data structureFlat, tabular data fits perfectly
Human editability desiredText editor is sufficient

Stage 2: SQLite Database

Recognizing the Need for Change

Now if this script grows into a larger project that handles everyone at the company and the company keeps hiring more and more people, at some point parsing the file will start taking a lot of time.

Growth indicators requiring upgrade:

MetricCSV ThresholdProblem
Number of employees>1,000Slow parsing
File size>1 MBMemory issues
Query frequencyMultiple per secondFile I/O bottleneck
Concurrent access>1 userFile locking conflicts

The SQLite Solution

This is where a different technology might be considered. For example, storing data in a SQLite file could be decided upon.

What is SQLite:

AspectDescription
TypeLightweight database system
ArchitectureServerless, self-contained
StorageSingle file on disk
InterfaceSQL query language
SetupNo server installation needed

This is a lightweight database system that allows querying the information stored in the file without needing to run a database server.

Benefits of SQLite Migration

BenefitExplanationImpact
Indexed queriesFast lookups by any field10-100× faster queries
SQL flexibilityComplex queries without custom codeMore features possible
Data integrityACID transactionsReliability
No server overheadStill file-basedSimple deployment
Concurrent readsMultiple processes can readBetter performance

Performance comparison:

OperationCSV FileSQLiteImprovement
Find by email (10,000 records)~100 ms (linear scan)~1 ms (indexed)100×
Find multiple recordsMultiple file readsSingle query5-10×
Complex filteringCustom code neededSQL queryMuch simpler

When SQLite Is Appropriate

Using SQLite for the data probably works just fine for assigning Secret Santas at a company.

SQLite suitability:

Use CaseSuitabilityReason
Company-wide Secret SantaExcellentThousands of users, not millions
Single-machine applicationExcellentNo distributed access needed
Read-heavy workloadExcellentMinimal writes, many reads
Embedded applicationsExcellentNo server dependency
Mobile appsExcellentLocal data storage

Stage 3: Full Database Server

Adding Complex Features

But imagine that features keep being added to the service. So it now includes:

New feature set:

FeatureComplexityDatabase Impact
Wishlist creationUser-generated contentMore writes, complex queries
ML gift suggestionsAlgorithm processingHeavy computation on data
Gift history trackingHistorical data storageGrowing data volume
External service availabilityPublic accessConcurrent users
User accountsAuthentication/authorizationSession management

And since people at the company love the program so much, it has been made an external service available to anybody.

The Limitations of SQLite

Keeping all the data in one file would be too slow.

SQLite limitations at scale:

LimitationThresholdImpact
Concurrent writes~1 writer at a timeWrite bottleneck
Database size>1 GB performance degradesSlower queries
Connection scalingLimited by file lockingConcurrency issues
Geographic distributionSingle file locationHigh latency for remote users
Backup complexityFile must be copiedDowntime during backup

The Database Server Solution

A different solution is needed. A fully-fledged database server must be used, probably even running on a separate machine than the one running the Secret Santa service.

Database server advantages:

AdvantageBenefitExample
Concurrent connectionsHundreds to thousandsMany simultaneous users
Advanced featuresReplication, clusteringHigh availability
Performance optimizationQuery planner, cachingFaster complex queries
Separate resourcesDedicated CPU/memory/diskBetter performance
Professional managementBackups, monitoring toolsEnterprise-grade reliability

Common database server options:

DatabaseTypeBest For
PostgreSQLRelationalComplex queries, data integrity
MySQLRelationalWeb applications, read-heavy
MongoDBDocumentFlexible schemas, JSON data
RedisKey-valueCaching, real-time data

Stage 4: Adding Caching Layer

Recognizing Database Bottlenecks

And there’s even one more step after that. If the service becomes really popular, it might be noticed that the database isn’t fast enough to serve all the queries being requested.

Database performance issues at extreme scale:

SymptomCauseImpact
Slow query responseToo many concurrent queriesPoor user experience
High CPU on databaseComplex query processingResource exhaustion
Connection pool exhaustedMore requests than connectionsConnection errors
Disk I/O saturationConstant reads from diskSlow queries

The Caching Solution

In that case, a caching service like memcached can be added which keeps the most commonly used results in RAM to avoid querying the database unnecessarily.

What is Memcached:

AspectDescription
TypeDistributed memory caching system
StorageRAM (volatile)
Access speedMicroseconds
PurposeReduce database queries
ArchitectureKey-value store

Caching Performance Impact

MetricWithout CacheWith MemcachedImprovement
Database queries/sec10,0001,00090% reduction
Average response time50 ms5 ms10× faster
Database CPU usage80%20%75% reduction
Requests servedLimited by DB10× moreMassive scalability

Common cached data:

Data TypeCache DurationExample
User profilesHoursName, email, preferences
Wishlist dataMinutesCurrent wishlist items
Gift suggestionsHoursML algorithm results
Popular queriesMinutesTrending gifts, common searches

Data Storage Technology Progression Summary

The Evolution Path

The progression has gone from hosting the data in a CSV file to having it in a SQLite file, then moving it to a database server, and finally using a dynamic cacher in front of the database server to make it run even faster.

Technology progression table:

StageTechnologyUsers SupportedData SizePerformanceComplexity
1CSV file<100<10 MBSlow for queriesVery low
2SQLite<10,000<1 GBGood for readsLow
3Database server<1 million<100 GBExcellentModerate
4DB + CachingMillions+UnlimitedExceptionalHigh

When to upgrade:

FromToTrigger
CSVSQLite>500 users or frequent queries
SQLiteDatabase server>5,000 users or concurrent writes
DatabaseDB + Cache>100,000 requests/day or slow queries

User-Facing Infrastructure Evolution

Similar Progression on the Frontend

A similar progression can happen on the user-facing side of the same project.

Stage 1: Email-Only Interface

Initially, the Secret Santa service would simply send emails to the people on the list. That’s fine if it’s a small group and there’s one person in charge of the script.

Email-only characteristics:

AspectSpecification
InterfaceEmail notifications only
ControlSingle administrator
User interactionPassive (receive email)
ComplexityMinimal
ScalabilityLimited to script execution

Stage 2: Simple Web Server

But as the project grows more complex, having a website for the service would be desirable to let people do things like check who their assigned person is and create wishlists.

Basic website features:

FeaturePurposeUser Benefit
Assignment lookupCheck gift recipientOn-demand access
Wishlist creationSubmit desired giftsBetter gift matching
Profile managementUpdate contact infoUser control
Gift historyView past exchangesNostalgia, tracking

Initially, this could just be running on a web server on the same machine as the data.

Simple web server architecture:

ComponentLocationRole
Web serverSame machine as databaseServe HTTP requests
Application codeSame machineBusiness logic
DatabaseSame machineData storage
Static filesSame machineHTML, CSS, JavaScript

Web Service Scaling Progression

Stage 3: Adding Varnish Cache

If the website gets used a lot, a caching service like Varnish might need to be added.

What is Varnish:

AspectDescription
TypeHTTP accelerator/reverse proxy
FunctionCaches dynamically generated pages
StorageRAM-based
BenefitReduces backend load

This would speed up the load of dynamically created pages.

Varnish performance impact:

MetricWithout VarnishWith VarnishImprovement
Page load time200 ms20 ms10× faster
Backend requests100%10-20%80-90% reduction
Concurrent users supported1001,000+10× capacity

Stage 4: Load Balancing and Distribution

And eventually, this still might not be enough. The service might need to be distributed across many different computers and use a load balancer to distribute the requests.

Distributed architecture:

ComponentCountPurpose
Load balancer1-2Distribute requests
Web serversMultipleHandle HTTP requests
Application serversMultipleExecute business logic
Database serversMultipleRead replicas + primary
Cache serversMultipleDistributed caching

Load balancer benefits:

BenefitDescription
Horizontal scalingAdd servers to increase capacity
High availabilityService continues if server fails
Geographic distributionServers in multiple regions
Health checkingAutomatic failover
SSL terminationCentralized certificate management

Cloud Infrastructure vs On-Premises

The Hosting Decision

This could be done in-house with separate computers hosted at the company, but this means that as the application keeps growing, more and more servers need to be added.

On-premises infrastructure:

AspectCharacteristicChallenge
HardwarePhysical serversUpfront capital cost
Capacity planningFixed capacityOver/under provisioning
ScalingManual server additionSlow to scale up
MaintenanceIn-house team requiredOngoing operational cost
ReliabilityDepends on local infrastructureSingle point of failure risk

The Cloud Advantage

It might be easier to use virtual machines running in the cloud that can be added or removed as the load sustained by the service changes.

Cloud infrastructure benefits:

BenefitDescriptionImpact
Elastic scalingAdd/remove servers automaticallyMatches demand
Pay-per-useOnly pay for resources usedCost optimization
Geographic distributionDeploy globally easilyLow latency worldwide
Managed servicesDatabase, caching as a serviceReduced operations
High availabilityBuilt-in redundancyBetter reliability

Cloud vs on-premises comparison:

FactorOn-PremisesCloudWinner
Initial costHigh (hardware)Low (no upfront)Cloud
ScalabilityManual, slowAutomatic, instantCloud
ControlCompleteLimitedOn-premises
MaintenanceIn-house teamVendor managedCloud
Predictable workloadMore economicalLess economicalOn-premises
Variable workloadWastefulCost-effectiveCloud

User-Facing Technology Progression Summary

The Frontend Evolution Path

Frontend progression table:

StageTechnologyUsers SupportedFeaturesComplexityCost
1Email only<100NotificationsVery lowMinimal
2Simple web server<1,000Basic CRUDLowLow
3Web + Varnish<10,000Dynamic cachingModerateModerate
4Load balanced<100,000High availabilityHighHigh
5Cloud distributedMillionsGlobal, elasticVery highVariable

Upgrade triggers:

FromToWhen
EmailWeb serverUsers request self-service
Simple web+ VarnishPage load times >500ms
VarnishLoad balancedSingle server insufficient
On-premisesCloudUnpredictable or global traffic

Principles of Appropriate Technology Selection

The Right-Sizing Principle

These examples show how important it is to find the right solution for each problem.

Right-sizing guidelines:

PrincipleExplanationExample
Start simpleBegin with minimal complexityCSV before database
Evolve incrementallyUpgrade when needed, not beforeAdd cache when slow
Measure before changingKnow current limitationsMonitor performance
Consider total costInclude development + operationsSimple = less maintenance
Plan for growthUnderstand next stepDesign for easy migration

Avoiding Over-Engineering

It makes no sense to deploy a multi-server web service with a distributed database for storage when there are only going to be a few dozen users.

Over-engineering consequences:

Over-Engineering ChoiceProblemBetter Alternative
Kubernetes for 10 usersMassive complexity overheadSingle server
Distributed database for 100 recordsUnnecessary operational burdenSQLite
Global CDN for local usersWasted costSimple web server
Microservices for simple appDevelopment + deployment complexityMonolith
Machine learning for simple rulesEngineering effort wastedIf/else statements

Monitoring for Growth Signals

Attention must be paid to how the service is growing to know when to take the next step to make it work best for the current use case.

Growth monitoring metrics:

MetricMonitor ForAction Threshold
Response timeIncreasing latency>500ms for user-facing
Error rateFailed requests>1% errors
Resource utilizationCPU, memory, disk>70% sustained
User countGrowing user base10× growth
Data volumeDatabase sizeApproaching limits
Query complexitySlow queries appearingExecution time >1s

Technology Evolution Decision Framework

When to Upgrade

Current StateProblem IndicatorsNext StepWhy
CSV fileFile >1MB or >100 usersSQLiteIndexed queries
SQLite>5,000 users or concurrent writesDatabase serverBetter concurrency
Database serverQuery times >100msAdd cachingReduce DB load
Single web serverCPU >80% or response time >500msAdd VarnishCache pages
Varnish + webStill slow or need HALoad balancerDistribute load
On-premisesUnpredictable trafficCloudElastic scaling

When NOT to Upgrade

SituationTemptationWhy Resist
Small user base“But it might grow!”YAGNI (You Aren’t Gonna Need It)
Acceptable performance“Latest tech is cool”Don’t fix what’s not broken
Tight budget“Enterprise features”Cost-benefit doesn’t justify
Simple requirements“Scalability prep”Over-engineering wastes time
Stable workload“Cloud is trendy”Stable workload = on-prem cheaper

Balancing Current Needs vs Future Growth

ConsiderationCurrent-FocusedFuture-FocusedBalanced Approach
DesignMinimal viableHighly abstractSimple + extensible
TechnologySimplest workingCutting-edgeProven + appropriate
InfrastructureBare minimumOver-provisionedRight-sized + scalable
CostMinimize nowInvest heavilyOptimize for ROI
TimelineShip fastPerfect foundationIterate quickly

Conclusion

Technical solutions must evolve alongside system growth and changing requirements. A solution effective for one scale or complexity level may become inadequate as systems expand, necessitating technology upgrades at appropriate thresholds. The Secret Santa application example demonstrates this progression: starting with simple CSV file storage suitable for small teams, evolving to SQLite when company-wide deployment required indexed queries, upgrading to a dedicated database server when feature complexity and external access demanded better concurrency, and finally adding memcached caching to handle extreme query loads by storing frequently accessed data in RAM. This data storage evolution from CSV through SQLite and database servers to cached database architectures mirrors similar progression on the user-facing side, starting with email-only notifications, adding basic web interfaces, implementing Varnish for page caching, distributing across multiple servers with load balancing, and potentially moving to cloud infrastructure for elastic scaling. The fundamental principle is right-sizing solutions to current needs—deploying multi-server distributed databases for dozens of users represents wasteful over-engineering, while running CSV files for millions of users creates severe performance problems. Monitoring system growth through metrics like response times, error rates, resource utilization, and user counts indicates when evolution to the next technology tier is justified. Over-engineering wastes resources and increases complexity, while under-engineering creates technical debt and poor user experience. The balanced approach builds for current scale plus one level of anticipated growth, monitors actual usage patterns, and executes upgrades based on measured need rather than speculation about future requirements. Success comes from choosing appropriately scaled solutions, monitoring growth signals, and evolving infrastructure incrementally as actual needs emerge, ensuring each technology choice matches current use case requirements without unnecessary complexity or insufficient capability.


FAQ