3 ms·
I don't get this. Aren't protocols basically interfaces? So the argument is "Start writing an interface, not a class?" Isn't this common knowledge? This is stuf
by kootling 6y ago
I don't get this. Aren't protocols basically interfaces? So the argument is "Start writing an interface, not a class?" Isn't this common knowledge? This is stuff you learn in programming 101. (I'm not trying to come off as snarky; I'm genuinely curious.)
- deleted 6y ago[deleted]
- mikekchar 6y agoThere are 2 general approaches for design when doing something that is vaguely object oriented. One is to decompose you data into structures, figure out the entity-relationships (often with a diagram) and then finally decide which operations should live on which object. When I first started out in the 80's this was pretty much "the way". You would frequently write descriptions of the domain, circle all of your nouns and underline your verbs. Then you would make data structures with the nouns and make methods with the verbs. A lot of this stuff came out of the Simula branch of OOP. It's the kind of stuff that C++, Java, C#, etc was modelled around. Objects are an encapsulation of data along with their operations. The other way to go is more where the Smalltalk guys went. In this branch of OOP, what's important are the messages. Data is abstracted out and your goal is to refer to it as little as possible. Instead messages are passed around between objects and the objects are responsible for dealing with the messy business of handling the actual data. When you are designing you look for the message flow and then build objects that handle the messages. When one says "Start writing an interface, not a class", I think what is meant is that you should concentrate on the messages that the objects need to react to, not the data within the classes. So you are designing a protocol, not an E-R diagram. There are people who are adamant that only one of these two approaches will result in "good code". Often there is a considerable amount of derision for someone who believes in the opposite approach. The truth probably lies somewhere in between IMHO. There are advantages and disadvantages. When doing a data centric approach, it's very easy to understand the state that you are capturing. But it's also very easy to let the details of the data dominate and to create unnecessarily complex code dealing with that data. Often you end up with god objects and poor decomposition of behaviour. On the other hand, if you go for the protocol approach, often you get designs where the state is almost impossible to figure out and where you have "big bags of functions" because it is convenient. It is difficult to maintain the data abstractions and often the data details leak out, pretty much destroying your design. Design is super difficult and requires a lot of experience of doing it. Different schools of thought and descriptions of approaches are helpful to a certain degree, but the best is to write a lot of code and get feedback from people with experience. My biggest piece of advice for people who are near the beginning of their career (i.e. first 10 years or so) is to try to work on an project (likely your own side project) for at least 5 to 10 years so that you can see it implode under its own weight. The biggest mistake I see developers make is assuming that things that appear to work for a year or two will continue to work as the code base ages. Especially I find people who have formulaic approaches to design often break the design badly in the long term (there are some 3 letter abbreviations that I could splash out if I wanted to pick a fight ;-) ) Unfortunately, these people rarely work on a project for more than a year or two, so you get what I call "drive by designings" -- just shoot it to pieces and drive on.
- hnick 6y agoWould a summary of the two approaches being whether you focus first on what the object does vs what the object knows? Drawing a Class Diagram of data fields was indeed the only way we learned ~20 years ago. But now that you mention it I find myself slipping into the other model a lot more lately. It's an especially natural fit for APIs.
- mikekchar 6y agoHa ha! I've tried to answer this question a few times tonight, but alas I find that I am not able to do so :-) It's a good question and I think the answer is much more deep than it appears. Maybe one day I'll be able to answer it.
- geofft 6y agoThe first part, yes, but the second part (the meat of the article) is more interesting and is making a claim of a better approach than just "write an interface": write an interface that returns some concrete set of values that you can work with instead of calling functions in some other interface. This reminds me a bit o the "sans IO" model for writing network protocol implementations: https://sans-io.readthedocs.io/ https://sans-io.readthedocs.io/ By having your HTTP protocol implementation accept a value input "These bytes were received" and return a value output "Please send these bytes" instead of directly calling read() and write() methods from an interface, you can write an asynchronous upper layer API using your favorite async stack as easily as a synchronous one - you're no longer baking in the idea that the library handles making the operations happen and therefore sometimes blocks in a read. (And the lower-level library is also testable without mocks, etc.)
- rubyn00bie 6y agoIn Swift this brought a specific reward, or did, but it's been a few years since I was hardcore writing Swift so forgive me if my memory is a bit off or perhaps I didn't fully understand it but... When I was writing a lot of Swfit this approach was substantially more banger than just being an interface, but it had a caveat-- your structs needed to be less than like four members (maybe three?) and if so Swift would just use the stack without having to do a bunch of heap allocations like with a class (or even a large struct). That is to say, the compiler and runtime had a trick this sort of pattern unlocked. I'd even guess now there's something extra going on under-the-hood by the Siwft compiler to make this style of programming moar gooder... but I'm super out of date with my Swift knowledge.