Advanced iOS App Architecture Flashcards
Pragmatic 7 steps you can take to ensure your architecture is effective:
Understand the current state of your codebase.
Identify problems you’d like to solve or code you’d like to improve.
Evaluate different architecture patterns.
Try a couple patterns on for size before committing to one.
Draw a line in the sand and define your app’s baseline architecture.
Look back and determine if your architecture is effectively addressing the problems you want to solve.
Iterate and evolve your app’s architecture over time.
The reality is that selecting an architecture pattern is less important than
understanding the the problems you’re trying to solve using architectural patterns.
Taking the time to understand the problems you want to solve allows you to focus on the few aspects of architecture that really make a difference. While many problems will be specific to your project, there are several general problems you can solve through good architecture.
Here are several problems that, when present, lead to slow velocity and fragile code quality:
My app’s codebase is hard to understand.
Changing my app’s codebase sometimes causes regressions.
My app exhibits fragile behavior when running.
My code is hard to re-use.
Changes require large code refactors.
My teammates step on each other’s toes.
My app’s codebase is hard to unit test.
My team has a hard time breaking user stories into tasks.
My app takes a long time to compile.
Understanding root causes
Each of these problems can be caused by two fundamental root causes: highly interdependent code and large types.
Explain Highly interdependent code problem
Properly encapsulating your code
Code becomes highly interdependent when code in one type reaches out to other concrete, i.e., non-protocol, types. Making one part of your code depend on another is extremely easy. This is especially true when a codebase has a lot of visible global objects.
Without properly encapsulating your code, your interdependencies can run rampant! The more you tightly couple parts of your codebase, the more likely something unexpectedly breaks when making code changes. This is further complicated by large teams with multiple developers because everyone needs to fully understand the interdependencies, which on very large teams may be an impossible task.
Explain large types problem
breaking large types into smaller types is a great way to improve your codebase’s architecture.
When creating a new type, you have to think about so many things:
What should the type be responsible for?
How long should instances of this type live for?
Should any existing code be moved to this type?
What if this new type needs access to state held by another type?
Explain My app’s codebase is hard to understand problem and questing to solve this problem
How long are your class implementations?
A good architecture breaks large chunks of code into small, modular pieces that are easy to read and understand. The more an architecture encourages locally encapsulated behavior and state, the easier the code will be to read.
How many global variables does your codebase have, and how many objects are instantiated directly in another object?
The more your objects directly depend on each other and the more your objects depend on global state, the less information a developer will have when reading a single file.
Carefully managing dependencies is a universal aspect that can be applied to any architecture pattern.
How differently are your view controllers implemented across your app’s codebase?
be able to easily reason about how the current file you’re editing is connected to the rest of your codebase - the best way to do it?
is to limit object dependencies and to make the required dependencies obvious and visible.
The structure of a codebase determines how much
code you can re-use
Large types can prevent your code from
being reusable
This is important: Reusability is not just about being able to re-use code. It’s also
about being able to move code around when making changes to your app. The more reusable everything is, the easier it is to shuffle code around without needing to do risky refactors.
what makes code hard to replace?
large types and highly interdependent code.
To summarize, you’ll be able to build features much faster if your app’s architecture allows
your team to easily parallelize work by loosely coupling layers and features that make up your codebase.
If your unit tests require a ton of set up, or if your unit tests perform uncontrollable side effects such as networking and persistence, then
your app’s codebase could benefit from an architectural refactor.
Here are some problems that can be solved with architecture in order to increase your
code’s agility
I find myself locked into a technology.
I’m forced to make big decisions early in a project.
Adding feature flags is difficult.
Clean Architecture and Ports & Adapters patterns fit really well into apps that have
a lot of local business logic. If your app is presentation heavy and doesn’t have a whole lot of local business logic, these patterns might not work well for you.
which pattern you select is less important
than how you put the pattern to practice.
The best way to decide which pattern to use is to
try a couple of the patterns in your codebase.