a coding pattern; replace supplied data with a supplier or a supplier with the supplied data.
it is very common to create code with an interface like this: do( Data supplied ) . we then use the data somehow to perform our functionality, whatever a do(…) method does.
on the other hand, sometimes we create code with an interface like this: do( DataSource supplier ) , and its body is basically the same as our starting chunk, but with a prolog that asks the DataSource for the Data and *then* performs whatever do(…) does.
so when we sketch a new function, we always have to mull over which of these two is the right thing to do. and when we refactor, similarly, we have to wonder which of these two ways to go. there is not a “right” choice you should always make. sometimes the supplied is the way to go, sometimes the supplier. but there *is* a right thing you should do, and that is to pay attention to the decision, as it has a variety of potential consequences.
here are some notions to mull over that might help you make your decision.
first, consider that you can do both. you can write do( Data supplied ) and do( DataSource supplier ) . i’ve assumed overloading, but you don’t need it, just change one of the names.) just have the supplier version contain the prologue we discussed and chain into the supplied version. note: please chain. don’t just copy the body of one into the other. doing that is purposefully injecting anti-change in to your codebase.
second, if you don’t do both, make sure that whichever one you do is the least awkward collaboration for you to test with. remember “awkwardness”? this is any property of a collaboration that makes it annoying for us to test whatever branching logic do(…) performs.
in java, for instance, streams can come from anywhere including files, but files can *only* come from a drive. if i have to write and maintain a bunch of files “somewhere else” to do my testing, well, that’s awkward. and when we have awkward tests, we don’t write/run/debug them.
third, regardless of picking one or both, is the object you’re passing in far fatter in interface than what do(…) needs to do its work? you might want to wonder if you need an intermediate object, one that is neither the supplier nor the supply, quite, but is a thin wrapper.
the business of passing around obese interfaces is extremely common in “it rubs the database on its browser” code, it dramatically increases the mental scope required to grasp and change the method. a typical case: passing a database connection (and an account id) when do(…) really just needs an account’s zipcode. you do understand that your database connection aims at a turing complete system, yes? it can do *anything* a computer can do. this issue isn’t just limited to the supplier choice. we do the same thing with supplied’s. again, you just want the zipcode. an account, whether databased or in RAM, has *dozens* of fields and operations.
you might think introducing an intermediate object is dumb, because even tho you *could* perform any of an account’s operations, you’re only really going to ask for zipcode, so why go to the trouble?
(ahhhhhh. here we strike at the very heart of the strictly technical aspects of the modern software development synthesis. change-enabling code is nearly always more valuable than shipping the next change. so begins another muse.)
the short answer is still twofold.
- cuz code that only gets the zipcode *must* be dead simple, and dead simple makes us go faster.
- when we realize we also need a) a state and b) a method to validate that they’re correct, we have a ready place to put it.
so. when you sketch a method or approach refactoring that method, consider your choices around passing supplier vs supplied vs both. consider both, consider awkwardness, consider interface width. there’s no right answer every time, but it’s almost always worth taking a minute and mulling it over.
go geek out, then.