I like the article. This is a great idea. I'm going to implement it over the next week. I have high hopes.
That being said, I have absolutely no clue what the advantage is to the python programming style exemplified in the article. Can someone explain why on earth I would ever want to convert:
In that contrived example, there is no point. In the real world, there are plenty of reasons to use a class instead of a function. Extensibility is the first that comes to mind. What answers are you expecting (i.e. performance)?
Great, you've now polluted the larger namespace and further exacerbated the need to thread data through a bunch of function calls. With a class, you could do something like:
class Actual_Step(object):
var1, var2, var3 # things needed for this
def run(self, context):
# set the vars somehow
self.part1()
self.part2()
self.part3()
def part1(self):
use var1
def part2(self):
use var2
def part3(self):
use var1, var2, var3
It's not stateless, but it works just fine. No polluting the larger namespace, and less threading a bunch of data through a bunch of calls. (Do you need the self.part1() bits in Python?)
2. You want to inherit. Maybe you have a collection of steps that all have the same setup/teardown bits, you can do this:
class Common_Base(object):
def setup(self, context):
...
def teardown(self, context):
...
def custom(self, context): # should be implemented by each derived class
...
def run(self, context):
self.setup(context)
self.custom(context)
self.teardown(context)
class Specific_Instance(Common_Base):
def custom(self, context):
...
And reuse that in multiple places.
3. Customizing at construction time. Maybe you have a step that goes out to some database, but what database may vary depending on what you're doing (for instance, at work we have test and ops modes):
And of course, since this is Python, you can change all of this to use a decorator or decorators and remove most of the boilerplate, but still retain the potential benefits.
In theory you could grow this (though at that point you may be better off with another system) so that different reports can be constructed from the steps themselves, without the need to execute them. Add elements like documentation strings that can be returned and prettified for different user interfaces or reporting purposes. All without ever having to touch the actual methods doing the work, just the way you interact with the classes holding them.
def make_thing_doer(db_name):
def f(context):
pass
return f
I think both examples are clearer and involve less boilerplate.
But I specifically asked why that initial example posted to the blog was written the way it was. I will stress that "because in the future you may want to do X or Y with it" is not a really good reason because there is absolutely no reason why you couldn't just replace the function when it came to that point.
Moreover, the database example you gave would require changing the code just as much as the function example I gave.
That doesn't implicitly inherit all the state. In which case I would concede that a class may be worthwhile. But as I already said, making the code so ugly initially is not justified by the possibility of eventually needing it to do this specific thing.
You can still make the code do this specific thing without ever needing to make it so ugly to begin with.
Nothing stops you from mixing the style and implementing __call__ in the class (or subclassing from a class which implements __call__ and calls run() if you don't like double underscores.
I mean, if you don’t like classes then don’t use classes. It’s not forced here. But if the author’s article is correct, they’re planning to change the script. Presumably they’ve done it enough to know a basic structure that’s worked well for them once they’ve started making changes. Why not set up that structure at the start if you know it’ll be the end result?
> Why not set up that structure at the start if you know it’ll be the end result?
Precisely because it's an unnecessary amount of code overhead.
There's no indication at all that IF he needed to expand the code that classes would be necessary UNTIL there were very specific requirements and there's also no reason why he should put that code in place in case of that requirement popping up.
It's always cheaper to write the simplest code you need at the time and then delete it (or rework some of it) and write the more complicated code you need in the future than it is to write more complicated code up front and expand less on some of it in the future.
If the point of the article is effectively "minimising the activation energy required to start automating a task" then surely the code should also be minimal?
It's more than one line though is it, it's a lot more _text_ even ignoring whitespace it's almost twice as much text. And that's the least important metric! Classes carry a lot more baggage. In the sense that if you see one, your expectations change and expand. The realm of possibilities expands too. This puts extra mental load when anyone new to the codebase has to look at it.
The fact that I looked at that code and spent 5 minutes trying to figure out why you would want classes there and what exactly it achieves is precisely what you want to avoid in codebases.
I audit code for a living, a lot of it, it takes far more work to audit code where the authors put a lot of unnecessary boilerplate or unnecessarily flexible code in place because it means I have to start figuring out what the authors intentions were. The expanded realm of possibilities means I have to check for more behaviors. It slows down the reading process.
There is no benefit in using classes that way. Technically, it's even harmful, because it has slight overhead. It's just poor style to have a consistent look for the script. You could just do the same with functions, and replace them one by one with classes when the demand for more complex code comes up.
Though, it's also possible that the writer simple did'nt know better and has not enough understanding of python, or thinks other people who might extent them lack those knowledge.
That being said, I have absolutely no clue what the advantage is to the python programming style exemplified in the article. Can someone explain why on earth I would ever want to convert:
into What is the point here?