
Much ado about iOS app architecture - prawn
http://aplus.rs/2017/much-ado-about-ios-app-architecture/
======
nielsbot
Generally agree with the article, but of course I have my disagreements.
Specifically:

> I consider Auto Layout one of the top 5, maybe top 3 technologies to ever
> come out of Apple. It’s beautiful, easy to work with and there’s nothing I
> can’t do with it.

It's not beautiful, nor easy to work with, nor does it work for every
scenario.

I am going to say something heretical: I have given up on auto layout and I
find "manual" layout _much_ easier. But that's because I rely on "one cool
trick"[1]: Do not lay out views using an x-y cursor. Instead, slice up the
bounds of the view being layed out using `CGRect.divide()`... So simple. If
you're using manual layout but not using `CGRect.divide()`, I urge you to give
it a shot it will change your life.

Of course maybe everyone does it that way and I'm the only person who thinks
it's a life-changer. :)

[1] Side note: I learned this trick from a technical interview at EA games
years ago... The best interviews are those where you leave knowing more than
when you went in, even if you don't get the job.

~~~
cageface
Dealing with auto layout is probably my least favorite aspect of iOS dev, but
I wouldn't recommend doing layout by hand. There are just too many variables
to consider to write really robust manual layouts.

That said I'm really disappointed with UIStackView. When it was first
announced it seemed like a great solution to a lot of common layout problems
but in practice I've found it tends to cause as many problems as it solves and
now I mostly just use it when I need a clean way to hide & reveal various UI
elements dynamically. I'd take some variant of flexbox over all this any day.

~~~
krzat
What problems did you have with UIStackView?

~~~
cageface
Adding or hiding elements often causes layout conflicts, because UIStackView
adds a new constraint at 1000 priority. You have to work around this by
bumping one of the other constraints down to 999.

Also recent versions of interface builder tend to complete fail at rendering
nested stack views, even though the layouts work fine when you actually run
the app.

------
flipgimble
While the article has a some good points about not over-engineering unless you
need it, I’m really put off by the pissed off and dismissive attitude. Ex
“here’s another wannabe who never bothered to learn”, “This pisses me off“,
“I’ve spent 15 years” etc.

This shows the author doesn’t really understand why you might decide to use an
architecture that departs from the apple MVC orthodoxy, and despite “years of
experience” never worked on a large, multi platform project, that tried to
avoid 1st party tool lock-in, or actually implemented in-depth testing beyond
the anemic xcode support.

The truth is that Apple mostly cares about providing a good UI SDK with
general platform services, but is agnostic about how any one app is
architected. It makes sense they will preach the simplest and most general
pattern: MVC.

Or how about not pissing on other people’s valid ideas because you are
offended and want to show off your own contrarian cleverness?

~~~
coldtea
> _Or how about not pissing on other people’s valid ideas because you are
> offended and want to show off your own contrarian cleverness?_

How about not calling other people's criticism "showing off", "contrarian
cleverness" and "pissing"?

------
nemothekid
> _1\. Write as little code as possible_

This is really sound advice that took me years to appreciate. Just like the
"Roll Safe"-meme, it always comes back to me in a similar expression like from
a now 8 year old blog post on MSDN - "Source code is a liability, not an
asset!" ([https://blogs.msdn.microsoft.com/elee/2009/03/11/source-
code...](https://blogs.msdn.microsoft.com/elee/2009/03/11/source-code-is-a-
liability-not-an-asset/))

------
mephitix
I generally agree with this sentiment.

VIPER is terrible except for maybe 1% of projects - and those projects I
envision having thousands of developers, dealing with legacy code, and fragile
infrastructure.

I've seen companies actively avoid auto-layout and storyboards because "it
messes up during merges", so then they turn to ridiculous code-based layout
which makes it impossible for designers to work with. However all those
storyboard format issues were resolved back in XCode 6 (or maybe even XCode
5). I think XCode 7 introduced storyboard references which allowed devs to
work on decoupled storyboards without any possibility of conflicts.

Anyway what I've landed on for production apps is something closer to MVVM:
Using Swift's protocol extensions for dependency injection without any
frameworks, and having a view interface over the controller for testing
business logic. There are other small tweaks, but for the most part, no crazy
frameworks, no fighting the system.

I don't agree with the idea that you HAVE to use MVC. You should try out some
of these ideas if you have the time/resources and see what works, what
doesn't. Make the call based on team/time to market/skills/performance
requirements/reliability requirements/etc.

If I'm writing a quick prototype app i'm going M(assive)VC all the way.

~~~
sAuronas
MVP sans the third-party frameworks works pretty well and is easy to read,
maintain and test. I prefer it to MVC, for sure, but if you really wanted
to... you could still write lightweight view controllers using a lot of
abstraction (and don’t forget to inject your dependencies). I have nothing
against VIPER, et al, but I think the author makes some really good points on
complexity and the inability to understand your system when you have to rely
on some of these architectural patterns.

------
on_and_off
Very interesting to read this from the other side of the pond (Android dev).

Android has a bit of a different architecture history : at first the framework
team has built it as modular components (IIRC you were not even supposed to be
able to subclass Application) with no recommandation on how to architect your
app code outside of that.

It lead to MVC with all the business logic in massive activities .. at least
for most companies.

We now have the same jungle of really abstracted patterns with some of them
actively fighting against the framework by rewriting it. To be fair, parts of
the framework like fragments have been a disappointment (and again to be fair
Google is hard working at addressing this).

I just want the minimum amount of abstraction that gives me the advantages I
want (separation of concerns, testability) and not rewrite everything from
scratch.

~~~
nsainsbury
Yes, I've noticed this a lot with Android projects too. Recently I looked at a
project that openly bragged about using: RxJava 2/AutoDispose, Conductor,
AutoValue, Glide, ThreetenABP, Inspector, PSync, Chuck, Scalpel, Stetho, Room,
Firebase, Butter Knife

Look, not all of those things are bad but jesus fucking christ, what happened
to exercising restraint and good judgement with introducing dependencies in to
your projects? Dependencies are a LIABILITY and for something to be introduced
it has to be worth it, not just provide some minor syntactical convenience
(like Butter Knife, etc.)

~~~
pjmlp
It is called CV driven development.

~~~
amigoingtodie
This made me laugh.

------
zoul
FWIW, my experience is almost exactly opposite. There’s not enough
architecture in the iOS world. The norm is to stitch together the app without
clear notion of the state or its transitions, everything is hidden in a giant
tangle of view controllers, a lot of the state is crammed into the app
delegate singleton, everything calls everything else via singletons and good
luck finding the UI flow in a web of storyboards where arguments are passed in
prepareForSegue. It’s a huge mess.

Talking about target-action or delegation in this context is IMHO a
misunderstanding. These are very nice and valid solutions, but in my
experience they are simply not enough to build a structured non-trivial app
with. They are the basic building blocks, but there has to be something above
them.

Of course, it’s also a mistake to go overboard with structure, drowning the
important bits in architecture boilerplate. Architecture cannot and must not
be followed blindly, as a cooking book. You have to aim for a reasonable
compromise, a point of diminishing returns.

~~~
bsaul
Agree with that. recently gave a talk at a iOS developper meeting, and less
than 5% of the dev heard about the concept of a "service layer"

------
MPiccinato
_> 2\. Don’t fight the SDK / tools_

I see this quite a bit in projects where devs haven't taken the time to
understand the SDK and tools/patterns provided by Apple. The biggest one I see
blundered quite often is the delegate pattern in favor of an
event/subscription system.

~~~
perlpimp
I see this everywhere. I think this enshrines difference between seniority of
a coder. new coders always want to write everything of their own. Senior
coders want to write nothing unless they have to, remain dependency free.
Learn standard vim / xcode / os keybinding etc etc. because at the end of the
day the more something unique is the less chance it can be immediately useful.
This works the other way too, defence against homegenity of a large pool of
other businesses / coders (but this one is about marketing and not writing
code). Great artists steal et al.

------
gwbennett
Article is right on! Read my mind. I've been a developer for 20+ years and iOS
developers since developers could write iOS apps. Mac apps before that. I
can't tell you how many hours I have had to fix "clever code" and clever
architecture.

It is so easy to jump into an app that follow the usual iOS design patterns.
As soon as I see NSNotificationCenter or Event bus garbage going on, I know
the app is a design/maintenance nightmare.

Keep it simple, following patterns like MVC, delegates and protocols. Keep
your view code, business code and controller code separate. That is 90% of the
issues.

~~~
thopkinson
concur. My experience exactly.

------
phreack
OP brings some great points (I've had a lot of trouble with an inherited code-
based UI in Swift), but I was dying to see code examples of the 'correct way'
to use UIKit and its patterns, particularly Dependency Injection, as I've yet
to find a solution that I'm comfortable with. Can anyone link a good example?

~~~
mephitix
Dependency injection is surprisingly easy with Swift since you can implement
it with protocol extensions. You don't need a framework or anything:

[http://www.danielhall.io/a-swift-y-approach-to-dependency-
in...](http://www.danielhall.io/a-swift-y-approach-to-dependency-injection)

------
htormey
One big problem with using interface builder to build UI is code review &
working on UI in parallel.

This isn’t an issue in smaller apps but if you work on a larger team (5+) it
becomes a real pain.

I really wish that Apple had taken the approach that Google did with using xml
(or something humanly readable) to describe the UIs generated by visual tools.

------
irrational
>Q: Should I write clever or obvious code? A: Always be obvious!

I love this. I feel like so much JavaScript code I've seen over the past few
years fails on this account.

~~~
mhd
What's obvious to some is obtuse to others.

Take iterating and filtering as a prominent example. For some, the functional
approach highlights the operations themselves and avoids boilerplate. For
others, the indentation of traditional loops and conditions alone is worth
that.

Usually there's a certain language culture attached to that. A Perl programmer
sees "map sort map" and knows what's going on, everyone else is just going
"Schwartzian what?". A big problem with JavaScript is that it doesn't have a
culture that points in a specific direction, so you're bound to encounter all
kinds of approaches, and none is really "native".

Swift probably isn't as bad, but it'll hit the same cultural barriers from
time to time, depending on the previous experience and general environmental
conditioning of the programmers.

~~~
kccqzy
I wholeheartedly agree. I’ll just mention that this is especially acute in
Haskell. Haskell is widely considered to be a language with a steep learning
curve, but for experts and experienced ones it is easy to lose track of how
advanced the code really is and how obtuse it is to a beginner. The lens
library is the best example. I often write extremely concise data structure
manipulation code that composes lenses, prisms, getters and traversals,
sometimes using (->) other times using Indexed as the profunctor. It’s obvious
to me but I’m sometimes told at code review time that it’s too hard to
understand.

------
wankerrific
I feel like this guy lifted the thoughts from my head and wrote them on his
blog. I agree 110% on everything here.

------
herodotus
I agree with most of this article, but an issue that he does not address is
the fact that Apple constantly "refreshes" the UIKit APIs - every WWDC shows
the new cool way to do something or other, and their own Apps usually exploit
these new things. Look at the Podcast App in iOS 11 for example - what used to
be a very simple table based app now uses collection views and fancy
presentation views that have multiple states. Unfortunately, App developers
face pressure for their Apps to look relevant, so it is not easy to ignore
these "improvements" to UIKit in ones own apps. Adopting the new UIKit stuff
inevitably leads to bloat.

------
mdhughes
As a Mac and iOS dev since 2005: For long-term survival and maintenance of
your software, XIB and autolayout are slow toxins, and Swift is a swift-acting
toxin. You won't be able to recompile your Swift code in a year. Or worse,
it'll compile but be semantically different.

You won't be able to edit a XIB without fixing AL issues in 1-2 years, and the
XIB will be unreadable in 5-10.

The part of Xcode that used to be Interface Builder is still useful for
prototyping, but don't ship that!

Write complex UI in code. Autolayout strings in code aren't as bad as the
obscure UI, but one can just as easily compute and set frames.

Choose any language except Swift.

Or, good luck with your walking-dead software.

~~~
saagarjha
Swift is slowly moving towards binary and source stability. Storyboards are
more capable then they used to be–and they're literally XML. How can you make
that unreadable?

~~~
mdhughes
Swift devs keep saying it'll get less fragile, then they rewrite "exceptions",
or how strings work, or anything else and all your code has to be fixed line-
by-line. I do not believe it'll be stable this decade.

Xcode stops supporting old features in XIB, or a class has a deprecated and
then removed property, and the deserialization fails. XIB is not XML with a
nice semantic DTD, it's an object serialization graph that happens to use XML.

~~~
valuearb
Nah, I switched to Swift at v1.0, the transitions have been relatively easy.
Right now our app has 90k lines of code so Swift 3 was a day of work, but
mostly automated.

Swift 4 is automatic. The trick to making the transitions easy is to not abuse
the language with too clever code. Write clear, straightforward and easily
msinatainavle code and it will rarely be broken.

------
bsaul
Small hijacking / ad. i recently posted this template of a (decently)
architectured app, to be used by anyone.

[https://github.com/SimpleApp/evc-swift](https://github.com/SimpleApp/evc-
swift)

It's focusing specificaly on the model layer (which i think most ios dev don't
spend enough time on). But, like OP, it's also advocating to stay extremely
close to the original MVC design. Free to use and contribute.

------
kp1234321
I could understand the frustration working on a smaller project solo or with a
few other developers. MVC is probably the best approach to get an MVP. But
when you work on an app with 100+ other developers and need to support
millions of customers, it's nice to have some more structured and verbose
architecture.

------
liamzebedee
As a full stack dev who has never written iOS apps, I have tried to understand
the conceptual basics and how they compare.

> Cocoa Touch is (I suspect) deliberately very simple: there’s Target-Action
> pattern, Dependency Injection, Delegate and MVC

Can anyone enrich this explanation?

~~~
programmarchy
Target-Action: A button needs to send a click action to a target handler.

Dependency Injection: A controller requires a service (e.g. access to some
API) to work, so it's injected into the instance typically by the constructor.
Think hierarchy or dependency graph.

Delegate: A table view draws cells in a table but it doesn't know how to draw
them, so it delegates this to something else, typically the containing view
controller. Data Sources are a similar concept but instead of asking the
receiver to do something it asks the receiver a question about the data it's
supposed to model. For example the table view would ask how many sections and
rows do I have.

MVC: Model (data), View (visual representation of data), Controller
(controlling flow of data to and from its visual representation).

~~~
LeoNatan25
> Target-Action: A button needs to send a click action to a target handler.

That is selling the responder chain very very short.

------
apple4ever
Number 4 is terrible and a big reason why I hate Swift.

Don't make the code so clever you don't know how it works.

Use Objective-C and you'll be good.

------
thopkinson
Yes. Perfectly expresses what I've observed time and time and time again
through the years. Nails it.

------
Apocryphon
So, just how did Square come up with this design pattern?

[https://medium.com/square-corner-blog/ziggurat-ios-app-
archi...](https://medium.com/square-corner-blog/ziggurat-ios-app-
architecture-b54b3f7132f0)

~~~
virmundi
Why not just use a message bus? Push new data into bus. Things listen for
that. Push reply on bus. Things listen for that. Update as necessary.

~~~
astrange
We call that NSNotificationCenter around here.

~~~
zoul
Except you can’t pull a well-typed object out of the notification. And have to
use a string constant to subscribe. And if you happen to want to filter the
notification stream or even _gasp_ map over it, you’re on your own. The amount
of boilerplate and subtle bugs around NSNotificationCenter is really not nice.

