Seed-And-Harvest Considered Harmful 13
Quite a while back I complained that a class is not a BASIC program, and more recently I blogged on my personal site about The Unspoken Parameter, but on further consideration I realize that these are both aspects of larger, well-known problem that vexes developers.
The real problem is the idea of seeding a function’s input in various places and then calling the program, and then harvesting the function’s results from the surrounding environment. This indirect access to input and output is troublesome and frustrates maintenance.
Seed-and-harvest programming was common in BASIC “gosub” programming, and I see it in some command line programs too. I see it in classes where methods take no parameters and have no return values and you must seed and harvest the object’s fields to make a successful test. I see it happening in poorly extracted test methods. I see it in java programs where you have to have a host of environment variables and files and command line parameters all set up to be harvested by the program.
Seed-and-harvest is daft. Every program is composed of input, process, output. We try to simplify and focus processing, but still I find code that does not take the same degree of care with input and output.
Since seed-and-harvest are bad, the degree to which the input and output are formal and direct is a goodness. It isn’t the only measure of goodness, but it is a goodness.
If I can call a function, passing everything it needs to know, and it returns a value indicating everything it has done for me, then I have an optimally direct and formal interface. Barring foolish and meaningless naming (or personal inability), I should be able to understand what it does fairly easily and without error. It is also far more likely to work in multithreaded environments, by the way.
If I must set environment variables or manipulate global data stores or even local data structures in order to call a function, then I have diluted the interface by relying on input seeding.
After calling a function, if I must to collect its output from the environment, global data structures, or local data structures, or various fields of the function’s object/class/module then the interface is diluted by harvesting.
An example of good here is a sensor object that emits a reading. The method to get a reading is obvious, clean, and likely to be thread-safe. A less good solution would leave the reading data in data fields of the sensor to be collected by a series of accessor calls. It defocuses the class re: SRP, while creating risk of update anomalies. It requires more effort from its clients than if it returned a reading.
This principle leads to other well-known principles. Dependency injection is a solution to a problem of indirectness. The Law of Demeter makes sense in the sense that it reduces the degree a method must reach to collect its input and to place its output.
In OO programs, static functions often have the most direct and formal interfaces since they can’t rely on instance variables. We know that static functions have problems with regard to substitutability in TDD, so we may make them non-static functions by moving them to a class or passing them by reference (closures and blocks). But we can see how much easier it is to read static functions than members, since we seldom have to read their code to understand what they are doing (though we may open them up to see how).
Objects with fields will exhibit some seed-and-harvest behavior to manage state and change of state, but we can preserve an otherwise direct formal interface with reference to callers of the object’s methods. We should not have to call a function to cause an effect and then call a number of accessors to get the results, as this would indicate we’ve diluted the interface with harvesting. We need to understand and bear in mind that we’re trading off some directness for convenience and encapsulation. If we know that we’re making that tradeoff then we are better equipped to do it well.
In end-user experience, this becomes more important. Plenty has been said by others about “direct manipulation”. They were wiser and earlier on the scene than myself; when it comes to UI I am still but an egg.
This concept is nothing new, even to me. I’m not saying it because I think it is something new. I’m saying it because I think people need to keep hearing it. It is simple but also profound.
Trackbacks
Use the following link to trackback from your own site:
http://blog.objectmentor.com/articles/trackback/178
Cool insight. Can you give an example of one of these functions?
“Every program is composed of input, process, output.”
Well, that felt very true in COBOL, but less in OO. Some objects have “state and behavior” instead, and may have long rich lives with interesting state transitions, no?
I don’t see the dichotomy here.
Behavior is always about some input(s) going through some process(es) and producing some output(s). It’s not all text filters and file processing, but it’s always transformations.
A parser takes in text and produces a syntax tree, but has a very rich life of state transition and a rich system of neighboring objects with state and behavior.
You can think of a GUI as a whole bunch of little programs (commands) in a special container, sharing a big library of objects if you want to. I’m hardly the GUI expert, but it seems that way to me. Conglomeration.
And in either case, the more direct and formal the input and output are, the more obvious the processing can be. True for methods, classes, file filters, and just about anything else. More importantly, the indirectness of input is always a hindrance to understanding how any subprogram works.
IMHO, anyway.
I don’t think there’s a conflict. I just thought the long life of an object might look a lot like the “seeding” Tim wanted to avoid. A parser has one input and one event – parse this. In my domain, an insurance contract is issued, has payments, bills, claims, life events, status changes, etc. The input – process – output is a lot less clear. Is its life bad seeding?
Ah. I see. No, it doesn’t have to be so. I intend the term to apply to a single function invocation.
I need a good example to talk to, I think. In my PySweeper dissection, I have a badly extracted method that mostly does its work on a list, but that list never appears in the parameters or returns. It’s main input and primary output is a secret as far as the method signature goes. Since managing that list is not the primary responsibility of the class, it is inobvious and needed refactoring.
I can’t show any of the test code where I’ve seen this, but I’ve seen multiple cases where a no-parameter,no-return method would create a object (or a set) and install them in containers somewhere in memory. I call those methods without ever touching the objects or the containers, so the big heuristic comes out:
You have to look at the actual code to find out what it is doing, not just to see how it does it. You can’t call that routine without having intimate knowledge of the code. That heuristic is bigger than Seed-and-harvest, but it’s part of the same picture.
I may have better examples later. I kinda hope not.
In Haskell “seed-and-harvest”-free functions are called pure functions, while environment side-effects (and the restriction thereof to sections of the program) can be modeled with Monads. I think this would interest you.
You can’t call that routine without having intimate knowledge of the code. That heuristic is bigger than Seed-and-harvest, but it’s part of the same picture.
A parser takes in text and produces a syntax tree, but has a very rich life of state transition and a rich system of neighboring objects with state and behavior.
Very nice article! Thanks for sharing your thoughts and corporate experiences. Looking forward for updates on this. Will definitely bookmark this for future reference.
Fantastic submit! I truly adore the way it is easy on my eyes along with the information are properly published. I’m questioning how I could possibly be notified when a fresh post has long been manufactured. I’ve subscribed for your rss feed which should do the trick! Possess a great day!
it true issue. Tottinger knows it …
Tüm dunyadaki okey oyunculari ile ayni platform içerisinde sohbet ederek canli okey oyunu oyna ve ve internette online oyun oynamanin zevkini çikar.
o my god nice just
It is true. I agree with what you’ve said and you can really give me advice in programming. To realize this idea. we need do more practice.