1. Picking the right architecture,
sticking to it and evolving it
Petter Holmström, Vaadin Architect
petter@vaadin.com
2. Even when you are doing agile development, the
architecture is something you want to design up
front, at least to some extent. It is also something you
want to get right from the beginning.
4. What is the project scope?
● What is the customer expecting?
○ Does the customer really know that?
● Changing or growing scope a common source of problems
● Red flag: “nothing fancy, just a few screens”
5. What are the Non-Functional Requirements (NFRs)?
● Make sure the customer and you are on the same page
● It is really easy for a customer to crank up the NFRs without thinking about the
consequences in terms of budget and schedule
● NFRs form the boundaries of your architecture
● Can be difficult and expensive to fix afterwards if you miss any of them or they
change during the project
● Examples: Availability, Performance, Consistency, Testability, Security, Safety,
etc.
7. Play it safe or experiment?
● Know your tools and make sure you have more than one
● Do some research, are there any new patterns or technologies worth taking a
closer look at?
● Can you try out a new approach in this project?
○ Yes, there are customers out there who are open to this. They are rare, but they exist.
8. To prototype or not to prototype
● High-risk features
● Nontrivial things
● Stuff you’ve never done before
● Remember: a prototype is a PROTOTYPE - no more, no less
9. Think about the future… but not too much
● You don’t want to overdesign
● You also don’t want to underdesign and end up refactoring everything later
● How could the scope and the NFRs change during the next e.g. five years?
● Is there any low hanging fruit?
● Are there any high-risk features you may or may not end up needing?
10. Hey - what could go wrong?
● Your system becomes too slow when the number of features and/or users
increases
● Your system becomes harder to maintain and extend as new features are
added and existing ones are refactored
● Your multi-threaded features start to behave strangely when the load
increases
● Your system or database does not scale well enough or does not scale at all
● Integrations with existing systems turn out to be more complicated than
anticipated
● You start to experience data integrity problems as your data model becomes
more complex
11. More things that can go wrong
● Problems in other systems cascade to your system or vice versa
● Your monolithic system must be turned into a distributed one or vice versa
● You have to replace the entire data storage system
● You have to replace the authentication and/or authorization system
● You have to replace the remoting protocol
● Remember Murphy’s Law
12. My opinion
● It is better to over design a little and end up with stuff you don’t need, than to
under design and end up refactoring everything later
○ You do not necessarily have to implement everything from the start, but design in a way that
makes it easy to add afterwards
● Still, try to KISS as much as you can
● Low coupling and high cohesion will take you far
13. Document the architecture
● An iterative process
● Remember who you are writing for!
● Keep it short and to the point
● My preference: a wiki, bullet points and diagrams
15. Design decisions
● Document all your design decisions
● If you had more than one alternative, list the others as well
● Developers will ask why you did this instead of that
● We have a short memory
16. NFRs
● Explanation of the NFR
● Metrics and how to measure them
● Tactics
● Priority
● Risk
20. Technical Design
● How to implement your conceptual design using the technology stack
● Deployment design
● Concurrency design
● Data design
● Security design
● List explicitly how each NFR is addressed by your technical design
22. Set up a testing environment!
● All components should be present
○ Remember: None, One, Many
● Replicated components should have at least two replicas
● Will you be running performance tests?
● Old hardware, RaspberryPi:s
● Cloud
● VirtualBox
23. Encryption
● “Add later when needed”
● Generate certificates and keys
● Distribute them
● Try it out!
● Yes, you can still change it later
24. Create a skeleton application
● Does not have to do anything but hum to itself
● Most critical components and interfaces should be present
● Run in your testing environment
● Try out with encryption enabled
25. Think about the developers
● Make sure you can easily run the application on your workstation
○ git clone; mvn clean install; run
● Mock external services if needed
● Make sure the developers have access to the testing environment
26. Set up an initial testing harness
● Unit tests?
● Integration tests?
● Acceptance tests?
● Performance tests?
28. Teach and explain
● Crucial that the rest of the team understands and accepts the architecture
● A complex architecture may seem like overkill in the beginning
● Encourage people to challenge your designs!
○ Preferably already during the initial design phase
○ You may have forgotten something
○ They may know something you don’t
○ Forces you to make valid arguments for each design decision
29. Strict or loose?
● Trade-off between developer productivity, consistency and future
maintainability
● Strict
○ Everything is always done in the same way
○ Easy for junior developer or maintenance developers who don’t know the codebase too well
○ Many code changes may be needed to implement a simple feature
○ Developer productivity may suffer
● Loose
○ Similar problems are solved in different ways depending on the context
○ The developers must understand what they are doing
○ Maintenance can become more difficult
○ Scalability may suffer
○ Increased developer productivity, at least in the beginning
30. Some examples
● Can you contact your persistence layer directly from the UI when retrieving
reference data or do you have to go through the service layer?
● Do you have to use DTOs in your UI or is it OK for your service layer to return
entities?
● Do you have to use Java interfaces for everything or can you let an object
access another object via its class?
● Can a facade/boundary invoke another facade/boundary or does it have to
invoke the service/control objects directly?
32. Talk with your colleagues!
● How are they planning to design and implement a certain feature?
● Have they run into something in the architecture that makes their everyday
lives harder?
● Or maybe they are even happy about the architecture!?!
● Avoid a “my way or the highway” or “whatever I don’t care” attitude
○ (Can be hard at times, especially if you are tired and keep getting your designs challenged by
the rest of the team members)
● You want your team members to come and talk to you!
● Keep an open mind - the architecture is not your baby
● The success of the project and the team is all that matters
33. Perform code reviews
● Especially important in the beginning
● Make sure the architecture is being utilized as you intended
● Correct misunderstandings or shortcomings in your design early
● Small changesets and quick reviews
● Don’t let this become a bottleneck!
34. Pay attention to the tests
● How much time is spent on writing tests vs. writing production code?
● What is the quality of the produced tests?
● Are the tests affecting the quality of the design in some way?
● Are they using introspection to access private members instead of using
package visibility?
35. Use static analysis tools
● You can’t review everything
● Red flags:
○ Big classes
○ Long methods
○ Classes and packages with circular dependencies
36. Test!
● Test early
● Test often
● Get the future users to try out the system ASAP
● The earlier you find a problem, the easier it is to fix it
38. The real world just called...
● Your architecture should make it easy to implement 90% of the features
● The remaining 10% should be doable but may require more work
● You have a problem if:
○ Your architecture makes it completely impossible to implement some of the features
○ Your architecture makes it increasingly difficult to add new features to the system
○ Your system fails to meet any of the NFRs
39. If you are lucky...
● You managed to identify possible problem spots in the beginning
● You kept an eye on them and saw the problem coming
● You already have a few cards up your sleeve
● Your intended solution might turn out not to work, but you still have time to
come up with another
40. If you are unlucky...
● The problem took you by surprise
● Lack of experience
● Misunderstandings
● Something that you thought would work didn’t
● The requirements changed
41. Key questions to ask
● What caused the problem?
● Why did you end up in this situation (the customer is going to ask you this)?
● Do you think you know how to fix the problem?
○ The perfect solution might not be a viable alternative at this stage in the project. Be prepared to
compromise!
● Will you need help or can you fix the problem yourself?
● Will the rest of the team be able to continue working while you are fixing the
problem?
● How long will it take to fix the problem and will it work?
● How will the budget and schedule be affected?
42. Finally
● If you are lucky, the required changes are small and can be performed without
fuzz
○ The architecture is evolving
● If you are unlucky, you have to have The Talk with the customer
○ The architecture requires a redesign
● Many smaller changes is better than one major change
● Getting it right is difficult! Remember that every failure is also a learning
experience!
○ Although I prefer learning from other people’s mistakes… ;-)