Skip to content

Instantly share code, notes, and snippets.

@ralfw
Last active July 30, 2018 14:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ralfw/bc9fafd1d80f4d96e3d1357c4455f932 to your computer and use it in GitHub Desktop.
Save ralfw/bc9fafd1d80f4d96e3d1357c4455f932 to your computer and use it in GitHub Desktop.
IOSP Example
void Classify(string number, Action<int> onArabic, Action<string> onRoman) {
if (int.TryParse(number, out var arabicNumber))
onArabic(arabicNumber);
else
onRoman(number);
}
/*
* Note how all details about how classification works are hidden in the function Classify().
* It's not visible to the outside wheter an "if" is used or a table lookup or whatever.
* In additon the classification also passes on an arabic number as an integer. If you're picky about the SRP
* this might be too much of a responsibility for Classify().
*/
var number = AskUserForNumberToConvert();
Classify(number,
onArabic: ProcessArabic,
onRoman: ProcessRoman);
//--- Alternative without IOSP
var number = AskUserForNumberToConvert();
if (NumberIsArabic(number))
ProcessArabic(int.Parse(number));
else
ProcessRoman(number);
/*
* This still is easy to understand. The process flow is straightforward. The condition details are hidden in NumberIsArabic().
* However, the mere decision that an "if" is sufficient for classification is visible. What, if more number classes have to
* be recognized? Then the whole approach would change to maybe a "switch" or some other means. This would have ramifications on
* the calling code.
* If the same happened in the IOSP solution then only more continuations would need to be passed to Classify().
*
* Also, the non-IOSP version is in violation of the SLA. Calling functions is on a higher level of abstraction than
* the "if" control statement - even here where the condition is wrapped in its own function.
* Behaviour creating language features are by definition lower level than integrations of behaviour creating
* language features (aka functions).
*/
@MikeBild
Copy link

MikeBild commented Jul 30, 2018

An extreme simple example, but interesting to analyze. A trifle should be noted. IMHO side effects (process) should handled in a higher integration layer.

business domain operation(s)

classify: promise<string> -> promise<bool>
toArabic: promise<string> -> promise<string>
toRomain: promise<string> -> promise<string>

framework/technical domain operation(s)

process: promise<any> -> promise<string>
branch: promise<string> -> promise<bool>, promise<string> -> promise<string>, promise<string> -> promise<string> -> promise<string>

integration

process(branch(classify, toArabic, toRoman))

...

input: promise<any> -> promise<string>
process(input(branch(classify, toArabic, toRoman)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment