One of the classic mistakes I've seen over and over is related to "just get it done" and "I'll clean it up after I get it working". Both of these lead to liberal and lazy use of imports. I know a few people addicted to "from module import *". In the cases I've seen, there is no meaningful reason for using that style except to avoid having to type long module names when you call functions and also to not have to think about what imports one actually needs.
I've seen cases where people have some problem with their code, so they spread imports all over the place until it works, then they develop further on that base. Or to avoid having to think about this at all, they import the hell out of everything at the start of every module under the sun, to guarantee that it's there when they need it.
I've always felt icky about this situation, pessimism telling me that it's bad, but lack of understanding preventing me from offering an explanation as to why it was bad. This week, I think I finally found an example of where this bites one in the ass.
Some code I'm reviewing has created 2 modules. Each module is a placeholder for at least one parent class, plus specialized subclasses. One of the modules also has a function declared right after the imports. Each of the two modules imports a third module in addition to importing each other. One problem became apparent to the developer when a runner script used both modules but had difficulty tracking down the function. A hack solution to create a shadow function in the other module which imported the previous module and returned the function of interest fixed things. When I ran the code through PyLint, it was complaining about the subclasses invoking the __init__ method of a non-direct ancestor, while not invoking the __init__ method of it's direct ancestor. All of this can be explained (I think) by the problems associated with circular imports. The section under the perhaps misnamed section "Recursive Imports" here seemed to jive with this problem.
The sciences are full of people who could care less about how import actually works but there has to be some happy middle ground for teaching import basics. PyLint can be used very effectively here to enforce decent standards and the more I think about it, a code checker should almost be a requirement in development, especially in the habit-forming days of a developer. In the circular import case above, the hackery associated with creating the shadow function could have been revealed by testing but also should have raised large red flags that required investigation. The "just get it done" syndrome seems to override these red flags and unfortunately, we seem to get away with it often, and for long periods of time, which reinforces the original behaviour, burying a learning opportunity until a really painful lesson comes along.
Oh well, I feel more informed now anyways. And I can pass that info on.
Monday, August 4, 2008
Subscribe to:
Post Comments (Atom)

No comments:
Post a Comment