The client had a legacy PHP codebase for Google Adword integration with a MySQL database that had become monolithic and difficult to modify. They wanted to replace it with a microservices architecture using Groovy, Cassandra, and separate codebases. However, this led to increased complexity, technical debt, and slower performance than the original system. It would have been better to take an incremental approach, keeping the system simple, and deferring optimizations until proven necessary by real metrics and business needs.
7. What the Client currently
has:
• PHP based legacy code base for Google
Adword API integration
• Large MySQL DB
• Monolithic Design
• 1 code base
• Difficulty adding new features
• Difficulty hiring developers
8. What the Client thinks they
need to replace it:
• Modern Dynamic Language (Groovy)
• MicroService Architecture
• NoSql (Cassandra)
• Spring Integration Modularization
• Asynchronous Processing
• 4 Separate Code Bases
9. What the Client is creating:
• Poorly designed code due to lack of expert technology
understanding
• Low Velocity due to time spend training
• Tech Debt due to difficultly refactoring across modularization
and separate repos
• Increased complexity — larger code base, and more
integration points then original design
• Slower!!! then original design due to numerous abstraction
layers, modularization and remote calls
• Long time to actualized Business Value due to Big Bang rewrite
10. What the Client really needs:
• Modern, but readily available Tech
Stack (Spring, SQL)
• Default Monolithic design, with
creation of services as needed
• Incremental improvements and
refactoring to shorten actualization of
business value
11. Result of Project:
• Dead lines not met / cost over runs
• Original project cost was $300,000
then $2,000,000 then “re-org”
happened, then many components
got scrapped and project was
simplified
12. Break down of initial design:
• Initial 3 months of development
• Google Add/Remove Functionality
• 4000+ Lines of code
• Difficulties with deployments, refactoring,
integrations
• Upfront technical optimizations and speculative
requirements made that boosted complexity and
scope by 10x+, business value was unproven or not
needed
13. Break down of simplified
design:
• 110 lines of code
• Single monolithic deployable
• Easy to refactor code
14. What should the client have
done instead?
• Deferred performance optimizations (MicroServices, Async, etc)
until implementation of business value and only when need justified
with REAL metrics
• "Premature Optimization is the root of all evil” Principle
• Deferred implementation of speculative business requirements
(Messaging , Cassandra) until business required it
• YAGNI/KISS (You Ain’t Gonna Need It, Keep It Simple Stupid)
Principles
• Given 2 implementation choices, and no clear proof either way,
always choose the simpler solution
• Ozzam’s Razor Principle
16. Dynamic Languages
• Dynamic Languages have the ability to greatly improve signal-to-
noise ratio of code
• .. and conseqently reduce lines of code, maintenance costs, and bugs
• XML, REST, Database, and File Operations in particular are much
shorter, and simpler
• Strongly consider Dynamic Languages (Groovy, Ruby) for projects
where performance is not bound by application (in our case it was the
DB)
• Groovy requires coaching / vigilance to ensure that developers take
advantage of extra abilities instead of just writing plain old Java code
( we didn’t always)
17. MicroServices
• Microservices have a substantial costs!!
• Extra difficulty in debugging, refactoring, and
deploying, performance hit, extra code required
for retry logic and contracts, numerous issues
with version mismatches of services
• Avoid, unless you really know what you’re doing,
and you’ve analyzed the costs and benefits (with
real performance metrics)
18. Developer Databases
• Shared database was a problem
• Use local developers database for development
• H2 proved to be an excellent embedded SQL
solution
19. Deployments
• Strive to make deployments simple, and easy to
debug
• Due to our design choices, a local end-to-end test
was time consuming and error prone
• A single monolithic war would have solved this
problem, and made debugging easier as well
20. Lines of Code (LOC)
• Lines of Code as a tool to measure complexity
• one metric that you can always get without
requiring complex tools
• each line of code is a liability
21. • Business loves metrics
• Sonar is freely and can be implemented from day one
to track LOC
• Get performance measuring tools in place from the
start if performance is a consideration
• Get performance metrics on original Legacy system
that you are replacing (I suspect our solution (PP)
was slower then the Perl it was replacing)
Sonar and Profiling Tools
23. Quotes:
Code is not an asset. It’s a liability. The more you
write, the more you’ll have to maintain later.
— Jez Humble
In deference to the gods of YAGNI, when in
doubt err on the side of simplicity.
— Martin Fowler
I'm wary of distribution and my default
inclination is to prefer a monolithic design.
— Martin Fowler
24. Quotes:
Don't leap into microservices just because it
sounds cool. Segregate the system into jars using a
plugin architecture first. If that's not sufficient, then
consider introducing service boundaries at
strategic points.
— Uncle Bob (Robert C Martin)
Done is better than perfect
— Mark Zuckerberg
25. Quotes:
Simple Design: The notion that it is best to keep the
system as simple as possible at all times
regardless of what we fear about the future.
— Kent Beck on XP
The Best Code is No Code at all
— Jeff Atwood