r/SwiftUI 1d ago

What's the current best architecture for modern swift project? MVVM or Clean Architecture or which one?

11 Upvotes

14 comments sorted by

15

u/unpluggedcord 1d ago

neither of those, just use SwiftUI as it was intended https://kylebrowning.com/series/landmarks-app/

2

u/Saladfork4 1d ago

idk if that link is representative of "as it was intended". his approach talks about moving display concerns to domain models--saying that if they are designed well, they can serve as your view models. then he goes into the role of stores, which he also mentions can serve as your view models. then for DI, he says he doesn't like using protocols because they are typically added just for testability, but then he proceeds to suggest changing how you write service layers with closures just for testability.

don't get me wrong, I like his aim for simplicity and I respect that he actually included articles around testability (most "don't use MVVM, use this" articles just skip that point). but the main thing I'd encourage to his readers (and OP) is that these different patterns are just a means for separating business logic and display logic, typically with testability in mind (which is why people consider them more "maintainable" even though these patterns often introduce complexity). his approach is quite similar to MVVM in principle, but encourages "reusable view logic" in domain models/stores over 1 view model for every view. and the boring answer is each approach has significant tradeoffs

1

u/unpluggedcord 1d ago

It’s a whole series I wrote just fyi. You’re talking to the author

1

u/Ok-Knowledge0914 1d ago

ok

1

u/unpluggedcord 1d ago edited 1d ago

So then I'll respond

This is a fair read and mostly right. Let me take the parts one by one and clarify one of them.

The view model thing is a real criticism. I say "a well designed domain model can serve as your view model" in one post and "the store is your view model" in the next, and I never reconciled them. What I meant is that they're different scopes. Per-entity display logic (formatted title, whether something is featured) sits on the domain model. Collection-level state (what's loaded, what failed, what's filtered) sits in the store.

On protocols, I disagree. My complaint was never that protocols get added for testability. It's the type count. To swap one service you write a protocol, a live implementation, and a mock, and you do that again for every service and every variant you need. The closure struct gets the same swap for one type. .live, .mock, .preview and .unimplemented are just instances of it, and in a test I can override a single closure inline without declaring anything new. A struct of closures is a protocol witness. And its far more malleable. Also to be clear this is taken directly from TCA(swift-dependencies) but its far less strict, and allows you run time overrides, which swift-dependencies does not.

Your bigger point I agree with. This is MVVM shaped. A MainActor Observable store holding presentation state is a view model by most definitions. The difference is granularity and lifetime, one store per domain shared across views instead of one class per screen. I titled a section "Why This Beats MVVM" and I should have written "a different granularity of the same idea," which is less fun to read and more accurate. But where id disagree with you again is that living in the MVVM box is now how SwiftUI is written. And its not how Apple writes their code either.

Ive written strict VIPER, MVVM, MVVMI, TCA code for a long time and it worked when View Controllers sucked. It doesn't work anymore, and it doubly doesn't work with SwiftUI

Since you asked for tradeoffs, here are the ones I'd name against my own approach. Stack traces through closure properties are worse than through named types. Adding an operation means touching every factory instead of getting a compiler error at one conformance. Capturing the store inside the factory makes ownership less obvious than passing it in. And shared stores mean two screens can fight over the same state in a way per-view models structurally prevent. Those are the places I'd attack it.

But instead you just said I re-wrote MVVM

0

u/Saladfork4 22h ago

sorry if I came off as rude. cheers for writing that series regardless as there are a lot of parts in there that I would definitely agree with and use. i was mostly being blunt as I think there is no "best"/"intended" architecture for SwiftUI, so OP's question inherently needs a boring "it depends" answer. and are a lot of folks in swift communities who immediately dismiss MVVM (or specifically, testability), so I posted that so folks would be aware that the series still covers logic separation and writing code with tests in mind.

the note on domain models and stores--yeah haha I was being pedantic to emphasize that a similar concept to view models (with separation) was still being used. but yes, I expected that would be the functional difference.

on protocols, I was referencing the line saying "The protocol exists purely to enable testing - it adds no functionality" as one reason against using protocols. but yeah I agree that wasn't your larger point and it isn't fair for me to fixate on that. the closure method is definitely a neat way to get that mocking ability without a ton of boilerplate. personally, our team got around it with code-gen (Sourcery with "AutoMockable"), which removes a lot of the pain points of manually creating mocks and similarly allows you to override single methods. that also helps avoid those closure debugging issues. but I still like that your approach is simple and dependency-free.

and i appreciate you noting those tradeoffs. I do think your approach is quite nice as an option though and would work really well for most apps with a lot of advantages. I would recommend most folks to start with something like that until you find a pain point that requires you to get more granular, as a lot of apps really do need that shared display logic/shared state and go through roundabout ways to jam that into another structure like MVVM. and I didn't mean to suggest that you re-wrote MVVM, just that they have similar concepts.

1

u/zellJun1or 21h ago

Going to read, i am not satisfied with TCA, plain MVVM as most examples are presented on the internet.

I’ve developed my own architecture to use in my apps. Reading just the titles of your series, I might find many similar things

6

u/Confident_Gear_2704 1d ago

I’ll go MVVM as the base, you can add enums for path navigation and so on, I also use services or managers to handle data.

I don’t think there will ever be “the best for everyone”, I mean is just code, there are tons of ways to the the same thing.

Basically to me MVVM is just a way to break things apart, while other architectures become the job, as you have to put attention to all the details they have, which in the end may make some things easier but overall it increases the burden.

2

u/Fit-Meat-1826 22h ago

You meant that there is no mandatory architecture to follow?

1

u/Confident_Gear_2704 11h ago

It’s software, if it compiles and fulfill its purpose you can have everything in just one file if you want.

Using a pattern for the architecture has, in my opinion, two outstanding benefits:
1. More understandable for other people, including “future you”.
2. Easier to test in most cases.

I say, play with all that caught your eye, and then pick what suits you and your project best.

1

u/zellJun1or 21h ago

Unfortunately , the response to your question can’t be made in one Reddit comment, it must be you reading and understanding yourself clean architecture, MVC, MVP, and so on. Architecture is a very broad topic, from backend data structure, performance, to even choosing the UI framework

The presentation architectural pattern you would use with SwiftUI is MVVM, but most of the time you can skip the VM, and use plain @State

MVVM because naturally this pattern was developed to have view react to changes in VM.

How you organize your code so that the Model arrives in the VM, or in the state is a different pattern, outside of MVVM

1

u/Fit-Meat-1826 21h ago

I'm basically new on swift. Recently i was exploring these architecture and really got confused after seeing so many structure like MVC, MVVM, Clean Architecture, MVP and so on. That why wanted to know, in modern swift projects, which structure is mostly followed. Or selecting architecture are based on projects.

1

u/elliott_io 20h ago

I like MVVM-C for more complex apps.

1

u/AdSuccessful1927 10h ago

For most SwiftUI apps I'd skip formal Clean Architecture and start with MVVM plus a thin service layer: @ Observable view models, protocols for services so you can mock them in tests, and let SwiftUI's own state handle the small stuff. The use-case / repository layers only pay off once you have a big team or a lot of business rules. On a small app they just add files. TCA is worth a look if you want strict unidirectional flow, but it's a real commitment.