IOSP 2.0
A more succinct definition leading to better code modularization - Radical Object-Orientation 101
To me the Integration Operation Segregation Principle (IOSP) is maybe the most important principle of clean code development. The reason: It’s so simple to follow. Because you can recognize if it’s been applied by looking at the code alone. IOSP code has a certain form. A form that supports understandability and testability.
I’ve defined the IOSP before:
And I’ve developed it in detail in my book from the original definition of object orientation:
It works great “under battle conditions” in projects when crafting new code or refactoring old code. I’m very, very happy with it.
A more succinct definition
But still… Sometimes I’m thinking there could be an even simpler definition.
And there is. The other day I came across one:
Integration Operation Segregation Principle (IOSP)
Let your functions be either Integrations or Operations.
Integration: A function composed only of calls to functions in the same code base.
Operation: A function composed only of calls to functions in another code base.
Operators (e.g. +, -, ^) and control flow structures (e.g. if-then-else, for, try-catch) are deemed to be also just functions in another code base: the standard library of a programming language. Or they are syntactic sugar for calling them.
What’s another code base? That’s obviously code you haven’t written yourself, e.g. a library or a framework from a 3rd party. In addition to that, though, also your own code can be considered “another code base”: that’s the case if you separate your code into libraries whose source code you “put out of sight”, i.e. which you really, really consider black boxes while writing a function in another part of your software.
If you want to give your own different code bases a telling form, wrap the code into a component (see here for a description of what I mean by that). The contract of a component pushes the implementation behind a border making it somewhat “foreign” or “3rd party” with regard to the code where you’re writing a function.
Or maybe even host your code in another service, i.e. pushing it even further out, making it an even deeper shaded black box.
The separate contract of a component and service to me is a barrier for change. It’s hiding details. It’s defining a service to be (re-)used in other code bases.
IOSP as a driver for modularization
Turning this around, the IOSP is a great help for modularization; and in that it’s core to Radical Object-Orientation. Because as soon as you feel hampered by the IOSP since it’s “forcing” you to keep logic down in the leafs of a function call tree, i.e. in operations, and those are growing bigger and bigger… you can wrap logic into a function and refactor it into another component, and call that in your operation. Like you do with a standard library function.
Of course, not only the IOSP should be applied to your code base, but also the Single Level of Abstraction (SLA) principle. So you’ll have to check your operations calling some of your components for “smoothness” with regard to the SLA. But in general I’d say it’s just fine to call your own functions living in another component from an operation.
Yes, I like this updated definition of the IOSP. Makes it easier to explain. Makes it a natural force for splitting up your code into modules.
I hope you like it, too.
For more context see my blog on Radical Object-Orientation:
Thanks for thoroughly explaining IOSP concept, really enjoying these series!
Still, I guess more "real-world"-ish examples would clarify the concept even further.
I still struggle to incorporate old knowledge into this new methodology. Like, how would you write proper Integration code without leveraging flow control? It does make sense sometimes to return early (e.g. don't do next steps of integration if result from previous step is invalid) or do basic loops based on step result etc.
Moving this into Operations kinda makes them do a bit more than their primary job e.g. check if previous step was valid.
Is it okay to have basic "ifs" in Integration, do early returns etc.? What would be your practical approach?
I am still trying to understand how all the concepts of IODA, IOSP fit together. I have read all the articles and your flow design book.
But this seems like violating PoMO and to loosen the IOSP?
And if you introduce the library calls in your operation code/functions don´t you introduce functional dependencies? But I guess your argument against this is, that the library code is a well tested black box which you do not count as functional dependency then?
I think you also introduce complexity, especially for testing when you need to instantiate and inject the library components.
And if the library code is behind a contract and you mock the implementation you loose the benefits of IOSP.
So I guess to solve all my concerns, the solution is to call to the library on the integration method above the operation and just pass then the data to the operation.
I am little bit confused :(
Regards,
Christian