POP was an exciting idea when it first came out, but in practice, it just doesn’t make sense to “orient” your codebase towards protocols. I’ve seen a project that was faithful to this and they came up with a codebase that’s extremely difficult to maintain and read because they made more abstractions than they need, and they defined so many custom types that the requisite vocabulary became huge.
Protocols have their uses, but MVC works really well and scales really well in making apps for Apple platforms.
Swift is multi-paradigm. Improved support (over ObjC) for functional style, protocol-oriented design, and value types has led many to overuse them.
Multi-paradigm isn’t a cop-out, it’s a pretty specific goal of the language. Being overly “faithful” to particular patterns will conflict with this, as you’ve likely experienced. I appreciate the ability to break out and use different styles where appropriate. That pesky “last 10%” is now far less painful. It also allows for varying styles per module based on functionality required and libraries in use.
“because they made more abstractions than they need”
If you replace protocol by trait, class, function, macro (basically anything that was invented to allow abstraction), the statement remains true, So I don’t think that’s a good argument against protocol-oriented programming.
If you’re not using protocols almost everywhere though, is your code really protocol-oriented?
I don’t even want to bother with answering that question, though. Even Apple didn’t have a clear definition for it, so debating this point seems moot to me, I’m afraid.
Rust pretty much only has protocols, and people seem to do fine programming with it. Type classes (protocols, traits) and regular classes are both different ways of achieving polymorphism, which every abstraction needs. It’s just a question of whether you think about your application as oriented around types or oriented around objects.
Yes, OO as defined by Alan Kay was about the interface, protocol or what ever we call it in a given language. It's a tool for abstraction, so you think about communicating instead of structure and state.
Now, most modern (~10y/o) general purpose languages I know have moved away from ADTs or simply inheritance. Inheritance was just a means to an end and never the point.
I made a new account just to ask this: 'MVC works really well and scales really well" Is this a joke? Do you have any professional iOS experience?
MVC is famous for scaling terribly on iOS and resulting in view controllers with thousands of lines. MVC is great for small apps. No need to overcomplicate things. But if you're building something bigger, you should look into using the right tool for the job. Don't blindly follow a popular pattern, but choose the right pattern to make the code easy to read, easy to test, and easy to modify.
There's nothing about MVC that makes you put thousands of lines in a controller. I don't know of any software development patterns that will stop you from writing spaghetti code or adopting "ball of mud" design if you decide to do that.
I'm not sure if I fully agree with that. It's true that you can spaghetti with any pattern, but I think on multi dev teams it helps to have guidelines about what goes where to ensure a clear separation of responsibilities. Someone linked another thought provoking article here about how MVC does not have to equal spaghetti which I found interesting. But I also think we need to take a step back and ask, "why have so many ended up with the same result?"
Well I also used to make giant controllers when I was a beginner. That’s why you can pretty much “spaghetti with any pattern”.
Over time I realized that I can just create dedicated controllers or handlers or managers or services with more specific and limited functionality, and then my VCs simply dispatch to those. It’s called composition.
that doesn't change the fact that you have a model in which 2 of the 3 roles just fuck around doing nothing, and 1 is doing everything (and has more classes). If you ask youself the question: "what does this logic belong to?" and most of the time it's the same good damn role, then are the roles useful as guideline?
I wrote "when you are in a situation..." - but that's not generally my experience, instead controllers are often cluttered with rendering details like colors and animations, networking code, or things that I would've put in the model layer.
To give some context, I remember reading an article about massive view controllers and one example was Firefox for iOS, so I've dug up a snapshot of its main view controller, which exhibits all the things people hate about Apple's MVC:
I have met Swift teams who would have proudly refactored this outdated MVC code into a "modern" MVVM pattern, replacing the 2000 LOC controller with one 2000 LOC ViewModel and a 500 LOC controller (because you still need UIViewControllers in the Apple world).
But in my opinion the bigger issue is the insistence of only having one controller, or view model, or whatever per screen. As soon as you find a way to divide all the interconnected concerns of this screen, the layers and their names are not really that interesting.
which begs the question what do you need MVC for, what is it if not a way of structuring code? If you can just structure your code by splitting to multiple files abitrarily, regardless of MVC
As I understand it, MVC is just how Smalltalk built its GUI toolkit: for each widget, the view did the rendering, the controller responded to user events and the model held the data. All the GUI toolkits that followed combined the view with the controller, which is why MVC seems to make no sense.
As for structuring your code, someone (I don't remember who) offered the suggestion that out of all the parts that the framework gives you, your application logic doesn't belong in any of them.
I don't think splitting up the controller part into multiple classes is a break from MVC. Nobody would demand that the view or model layer consists of a single class per screen, why should the controller layer follow this rule?
I actually agree with what you said in some way. Projects should start with whatever is the most boring, straightforward architecture possible, and then evolve it organically.
But for UIKit projects, that boring foundation is to vaguely follow Apple's idea of MVC, at least so that JSON parsing and font size adjustments don't happen directly in an IBAction.
back when I was still doing Android, there was this trend in Android to throw away Google MVC and just have everything as view (and none of fragment, activity and all that crap). The rest of your code you just slice up in ways that makes sense. You platform-dependent logic just reuses the same activity to access the junk google provides.
First, MVC isn’t flat. The (V)iew of an MVC triad can itself be an MVC.
Second, MVC is a UI pattern. Decouple your business logic from your UI. Put it in a utility or “service” layer (which itself can adopt patterns to manage complexity, as needed).
Do you realize that the whole Apple's UIKit Framework is a version of MVC?
I have seen many versions for it in iOS, MMVC, MVVC, or whatever, but really they are iterations of separation of business logic and view/display logic.
You can disperse the view logic, without having traditional centralized controllers, but your business logic will end up centralized in one place. So, in practice you end up with a Model-Business-Logic / View paradigm, where traditional controllers end up just being a thin layer.
Protocol driven development, reminds me the old Java style of having a class (eg. MyFunctionalityClass), which was either abstract, or had only protocols declared, then have another MyFunctionalityClassImpl to actually implement it.
I didn't think it was pretty, and it seemed it was done by C++ developers to simulate the lack for header .h files in Java.
Ps. Before you reply on a ad-hominen way, I probably have much more iOS experience than you, since I both have worked on it since day one, and have worked on some the currently largest apps in the world.
I basically agree with you, actually. It feels like a lot of this is breaking down into semantics. I’m not fond of acronyms, I believe it’s important to go to core principles and never do anything blindly, but only when it’s useful.
The fundamental challenge of iOS architecture is picking the right level of abstraction for the complexity of your application.
The trouble that comes in with MVC, as I see it, is how easy it is to shoot yourself in the foot. It’s too easy to do it “wrong”, which is why so many have tried to come up with something different. Of course you can’t escape the MVC-ness of the platform, it’s all about how you manage it.
I fully agree here - MVC scales terribly. Of course, it's not impossible to come up with a well designed MVC app at scale, but it takes a ton of skill and feels like you are fighting the framework at most steps.
One particular challenge is lack of modular components and component nesting. For example, if you have a list view, it's very natural to have one component define the list, and child components define each entry in the list. Something like React makes this trivial.
On iOS on the other hand, you are encouraged to use a UITableViewController with UIViews for each cell. This immediately pushes you towards one mega-controller which mixes the responsibilities of the list with those of the individual cells. To overcome this, you could try to have a UIViewController for each cell (uncommon), or have the UIView of each cell start taking on more responsibilities of a UIViewController (breaking MVC).
In general though, iOS's MVC is a perfect storm of being both bare bones as well as opinionated at the same time. For these reasons many large corporations have moved away from MVC to their own custom in-house architectures to handle scale.
> Is this a joke? Do you have any professional iOS experience?
Let’s just say that I can build a view controller for a large, multi-sectioned list where each section calls a different APIs and shows items with different layouts, and still end up with less than 500 lines of VC code even with generous line breaking. Oh, and I can make custom UICollectionView layouts with self-sizing headers and cells.
That said, your comment is just ad hominem and you should be downvoted to oblivion.
How do you manage data flow from your view layer to your API layer? Like for example, if a UITableViewCell has a button in it which needs to load some data from the API? Do use an event/delegate which flows from the UITableViewCell through the `cellForRowAtIndexPath` method to the controller, out to some other class? It must feel pretty great to have your business logic and API layers abstracted into other classes, and have your lean view controller just be the glue. Yay MVC!
Now imagine that your table view has 20 cells, and each cell is managed by a team of 5 people and needs 1,000 lines of code to fulfill its business logic. How would this approach hold up? Would you have all 100 people working on the same `cellForRowAtIndexPath` method, piping every event for those 20,000 lines of code through there?
When people talk about scale on iOS, they are talking about potentially 100s of people working on the same screen. With something like React, this is trivial by having each team work independently on its own components. With iOS, its much harder out of the box.
Yeah, sorry for the choice of words; I just fired something off with no editing. In my mind, I was thinking of MVC at it's worst (which is unfortunately common).
That being said, would love to learn more about how you structure code. What does a project structure look like for you? I usually conceptually try to separate the view and data starting with the simplest file structure and dividing as needed.
The problem is that the Cocoa framework, even after the advent of Swift, has always been created with MVC in mind. We're now at a point in iOS where trends have rolled around and now people are saying to pick MVC because that was Apple's intention, other architectures were created because people were doing it wrong:
Obviously most significant production apps are using variant architectures such as at the bare minimum having view models, and the introduction of SwiftUI and popular earlier frameworks such as RxSwift also complicates things. Most apps aren't using pure MVC, sure, but it doesn't mean that the architecture isn't scalable. The alternatives might also be pretty gnarly:
That's an interesting article. I find iOS architecture fascinating and spend a lot of time thinking about it. It seems like "MVC" in common usage (based on talking to other iOS devs) means spaghetti, but I guess it doesn't have to be like that.
To me that article proposes a more disciplined MVC than what I've seen in real codebases. I think a lot of the architectures people come up with (like the second one you linked) try to build that discipline in. I try not to be dogmatic and instead go to core principles. Do I know what this class is supposed to be doing? Are my data and view layers reasonably separated with minimal glue code? Can a new dev easily navigate this project?
It's an endless discussion with no right answer. Thanks for sharing!
This was popular in Java (see libraries with "Foo" interface and "FooImpl" class).
Sometimes it really is useful, but it was over-used in Java. A lot of times you don't even need a mock.
In fact a lot of times even a singleton is good enough. YAGNI. I don't think the example was good: in the "potential situation" where you actually need a second `UserDefaults`, you could've just find and replace. Maybe for a massive project, but I've never worked on something too big for doing things like to avoid Shift-Ctrl-F.
#2 is interesting...can you give an example solving circular dependencies?
Even if you had an interface, wouldn't you still have the implementations still causing a circular dependency?
You can turn A->B, B->A into A->I,B->A + A.I=B and that does avoid a circular dependency.
A->B means a depends on B, A->I means A depends on an interface, and A.I=B means that B is set as the implementation of the I interface that A depends on.
I’m on mobile so that was the best I could come up with. Try it out using Swift though, and that can be translated pretty directly.
The same problem exists in Swift. I inherited an iOS project a couple years ago where the original dev over-used protocols like crazy. The result is spaghetti code that's impossible to understand. Luckily we're mostly replacing it with simple encapsulation now.
This sort of thing is a common pattern in Go, where it is accomplished by the fact that Go interfaces do not require types to opt into them by declaring their adoption. If a type conforms to the interface it's a type of the interface.
So one can create a new interface type that supports the specific subset of functionality you need from a larger type that you don't control and use it in a similar way to Swift protocols.
I'm looking forward to using PoP more; especially as I move into SwiftUI (Which was designed for it).
Right now, I am still very much in polymorphic OO land, as I am working on a classic UIKit app (It's a bit of a kludge to use PoP in UIKit, as UIKit was designed with the classic MVP pattern in mind).
But I'm not a fan of dogma. It's just another tool. I sometimes use techniques I learned in the 1980s.
I have seen this a lot, am I the only one who thinks that this is ugly?
Crafting a protocol after the fact to match some class' interface (and then put an empty extension) seems just wrong.
I very much prefer to pass simple types around. (like two closures in this case) You don't need to remember any protocol name and don't need to define a ton of mock objects.
Protocols have their uses, but MVC works really well and scales really well in making apps for Apple platforms.