[HN Gopher] Swift Protocol Oriented Programming and Testing
___________________________________________________________________
Swift Protocol Oriented Programming and Testing
Author : geekylife
Score : 53 points
Date : 2021-07-30 15:46 UTC (7 hours ago)
(HTM) web link (arturgruchala.com)
(TXT) w3m dump (arturgruchala.com)
| solarexplorer wrote:
| 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.
| peey wrote:
| Suggestion: title should be renamed to "Protocol Oriented
| Programming and Testing in Swift".
|
| "Swift Protocol" is something else entirely
| https://docs.openstack.org/swift/latest/
| bww wrote:
| 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.
| monocularvision wrote:
| While you have to declare it, you can do the same in Swift
| using an extension.
| pixel_tracing wrote:
| Not that great of an example to be honest.
|
| For starters the use-case which was defined `UserDefaults` you
| can just use a property wrapper to make it easier. Then in your
| class you can do:
|
| @Defaults(key: "usesDarkTheme") var usesDarkTheme: Bool
|
| Now it uses type erasure under the hood and call sites are
| cleaner.
|
| For PoP, it's kind of outdated. Better to use Value Oriented
| programming nowadays
| amw-zero wrote:
| They go hand in hand, because values can still implement
| protocols.
| armchairhacker wrote:
| 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.
| liuliu wrote:
| Rule of thumb is always: if you need it, do it, otherwise,
| don't. Real world cases could be:
|
| 1. If you write a unit tests and really need to have a double
| of that particular component, then do it. Otherwise, don't.
|
| 2. You need to decouple the dependency (maybe these are
| circular), then do it. Otherwise, just take on it as a
| dependency.
| ratStallion wrote:
| #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?
| amw-zero wrote:
| 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.
| marcellus23 wrote:
| 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.
| 3grdlurker wrote:
| 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.
| mpweiher wrote:
| Well...it also wasn't really new, POP is just OOP by people who
| didn't understand OOP (and overcomplicated it)
|
| https://blog.metaobject.com/2015/06/protocol-oriented-progra...
| dgb23 wrote:
| Funny article!
|
| 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.
| ribit wrote:
| Unfortunately, the notion "OOP" has been taken hostage by C++
| and Java and they don't want to give it back.
| Apocryphon wrote:
| "Compiler Oriented Programming"... nice one.
| iddan wrote:
| Rust makes a great example of POP in scale. They are called
| traits there but it's the same thing
| 90minuteAPI wrote:
| 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.
| Someone wrote:
| _"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.
| 3grdlurker wrote:
| 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.
| jolux wrote:
| 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.
| swiftaccount1 wrote:
| 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.
| ardit33 wrote:
| 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.
| swiftaccount1 wrote:
| 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.
| Apocryphon wrote:
| 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:
|
| https://medium.com/flawless-app-stories/the-only-viable-
| ios-...
|
| 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:
|
| https://developer.squareup.com/blog/ziggurat-ios-app-
| archite...
| swiftaccount1 wrote:
| 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!
| smoldesu wrote:
| > I find iOS architecture fascinating and spend a lot of
| time thinking about it.
|
| > It's an endless discussion with no right answer.
|
| These don't seem like the hallmarks of a well-designed,
| mature platform.
| 3grdlurker wrote:
| > 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.
| gregkerzhner wrote:
| 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.
| swiftaccount1 wrote:
| 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.
| jmull wrote:
| 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.
| swiftaccount1 wrote:
| 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?"
| 3grdlurker wrote:
| 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.
| gregkerzhner wrote:
| 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 _.
|
| _ Facebook - https://www.youtube.com/watch?v=mLSeEoC6GjU. *
| Uber - https://github.com/uber/RIBs * Square -
| https://github.com/square/workflow
| mpweiher wrote:
| > MVC is famous for scaling terribly on iOS
|
| You have to distinguish between MVC, which scales really
| well, and what Apple _calls_ "MVC", which does not.
|
| https://blog.metaobject.com/2015/04/model-widget-
| controller-...
|
| And yes, the fact that they overloaded the term is a problem.
|
| https://blog.metaobject.com/2017/03/concept-shadowing-and-
| ca...
| [deleted]
| ChrisMarshallNY wrote:
| 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.
___________________________________________________________________
(page generated 2021-07-30 23:01 UTC)