
On Wed, 20 May 2009 03:53:33 am Aaron Rubin wrote:
On Tue, May 19, 2009 at 10:14 AM, David Stanek <dstanek@dstanek.com> wrote:
Object Oriented: Because it is not functional-style programming, but instead OO, you have to give defintion as to what object type you are using before using it. This makes definitions and usage longer than in functional programming (when 80 character widths were invented).
That's a red-herring. Functional programming is quite capable of 80+ character lines too: FetchFrameGrabber(ExtractAbstract(GetFrameSource(GetHardware(MakePhazeMonkey()))))
PhazeMonkey.Hardware.FrameSource.Abstract.Framegrabber is an example
Such a deeply hierarchical call is poor technique regardless of what each level represents: classes, modules, function calls, or something else. It is reasonable for parts of your code that understand PhazeMonkeys to know that a PhazeMonkey has Hardware, but it is completely unreasonable for that same section of code to rely on the existence of PhazeMonkey.Hardware.FrameSource.Abstract.Framegrabber. That sort of tight coupling between the top of the hierarchy and the bottom defeats the purpose of encapsulation. I see that in a later post, Aaron writes: "The Law of Demeter applies to objects referenced second-hand. The class name given is an example of a hierarchy of modules, not one class reaching through a second class to get at the class members it uses." That's an irrelevant objection. Demeter is a design principle: it applies to classes, namespaces, military units, corporate business units or any hierarchical structure. Of all the military blunders in World War I, the one they never made was for General Haig to call up the front line and say "Hello, let me speak to Private Baldrick. Baldrick, I want you to take your rifle and point it due east and use your index finger to pull the trigger at 1700 hours precisely." Besides, modules *are* objects:
import math isinstance(math, type(math)) True
If you are using more than 5 or 6 levels of indentation you may be doing something wrong. I would guess that your methods are too complex or maybe you are violating the SRP.
See below for code example
Namely:
class a(object): def method1(simulation=False): try: if simulation: for x in range(10): if x>5: try: # here might begin some actual math, with two or three more levels of logic, interfacing with other libraries such as NumPy, etc. where you might need specific error handling except CustomError: # customer error handling
i.e. the logic code *started* at the 7th indentation level. But I'm sure you can find plenty of examples where it might be more.
Far too complex in my opinion. That's best refactored into separate methods or functions. For example: class A(object): def simulated_method1(self): self._common() def method1(self): try: for x in range(5): self._metha(x) for x in range(5, 10): self._methb(x) self._common() except CustomError: self._fallback() def _metha(self, x): """Return function(x), for 0 <= x < 5.""" assert 0 <= x < 5 def _methb(self, x): """Return function(x), for 5 <= x < 10.""" assert 5 <= x < 10 That's (possibly?) longer code, but it comes in single-thought-sized chunks. Each method does one thing, rather than wrapping a whole bunch of loosely-related functionality into a single method. Another advantage is that it reduces the amount of test code you need. Instead of what could be an exponentially large number of possible paths through method1(), each individual method only has one or possibly two paths that need testing.
I'd like to see an example of your variable names. I don't use hungarian notation and my name are usually under 10 characters.
I gave an example already in the snippet you quoted.
Namely "hasInstrumentControllerPhaseDither". Well, your naming conventions are yours, naturally, and you can use any convention you like, but I can't imagine ever willingly using a name like that. I would suggest that if you need to distinguish hasInstrumentControllerPhaseDither from (say) hasInstrumentWidgetPhaseDither, hasScannerControllerPhaseDither and hasInstrumentControllerAmplitudeDither in the one function, your function is far too complex, doing too many things, and should be split up into smaller single-purpose functions.
5) Monitors are getting bigger, wider, cheaper. This allows us to have two files, side-by-side on a screen that are *both* 120 character width (or even wider), without changing font sizes.
True enough for those editing on large monitors, AND who like viewing multiple files side-by-side. (Personally, I very rarely do, and then only when comparing two files line-by-line.) But have pity on those using a EEE or similar machine. Besides, if you can fit two 120-char wide files on screen, you can fit three 80-char wide files on screen. For what it's worth, although I've never needed to interoperate with code using .NET style guidelines or written a 100 KLOC program, I generally have very little difficulty in keeping 90% of my code below *seventy* characters per line, including four-space indents, and virtually all of the rest below eighty. The short line-length encourages me to refactor my code so that every function does one thing and one thing only. -- Steven D'Aprano