3

One of the incidental complexities of introducing features to an existing system is that the programmer often has to touch several areas of code that are not immediately adjacent. Over the long haul it can be unclear when looking at a bit of code that it pertains to another bit found elsewhere. It's both ugly design and a maintenance hazard. One of the properties of superior code, in my book, is its ability to keep a concept localized in one place. Sometimes this is built in to an architecture up front making it easy to plug new features into a system.

In scripting languages where all classes remain open to extension at runtime, it can be easy to think of the language as its own platform and not go the route of formalizing how things plug in. An app written in a scripting language could accept a module whereby the module reaches out to the various system components and changes them -- adding aspects to functions, wiring into events, and so on. Essentially, because the architecture wasn't properly designed for extension, we utilize a poor-man's plug-in system and oftentimes this suffices. In effect, we eliminate the need to modify several spots directly and instead tweak the system perhaps in similar spots but in an automated fashion.

That's what I'm focusing on. We still need to modify things that are spread across our system, but we do so in a way that keeps the entirety of the change localized to a single file (module).

In there a design pattern/term for the practice of simply localizing all the code (even if it has tentacles) to a single physical location (its own file)? I'm not sure it's the plug-in pattern or the extensibility pattern because in many cases a scripted system may not have been designed with extensibility in mind; however, it is still possible to localize change. Would this simply be called modularity? I'm really just looking for a shared term that I can use to rightly convey the concept without all the explanation.

Mario T. Lanza
  • 1,700
  • 1
  • 13
  • 22
  • 4
    This is called [monkey patching](http://en.wikipedia.org/wiki/Monkey_patch), and it's an anti-pattern. It "often works", until two people try to patch the same piece of code. There's no *safe* way to extend something that's not designed for extension. Not even inheritance works that way. – Doval Jul 15 '14 at 17:04
  • The general implication (the term "anti-pattern") implies a bad thing. However, I would argue that short of rewriting the architecture for better extension, the property of localizing code related to a change is better than manually changing the code in several spots. Both suffer the consequence of potential long-term issues; however, monkey patching keeps all of the related changes in a single spot making the overall change more intelligible. – Mario T. Lanza Jul 15 '14 at 18:07
  • 3
    By that logic, a global variable is also good, because you only need to make the change in one spot and it applies to the entire system. Monkey-patching is the same as treating every single class, method, and function as a global variable. Modularity isn't about reducing the number of places you need to make changes in the source code; it's about reducing the number of ways one module can affect another. This necessarily involves separating one thing from another, and passing things around, but is still the better design. – Doval Jul 15 '14 at 18:12
  • Aspect-oriented programming is thus disallowed? Aspects are dynamically layered onto an object without that object's knowledge. – Mario T. Lanza Jul 15 '14 at 18:16
  • 1
    @MarioT.Lanza: aspect-oriented programming only works well for adding non-functional features like logging, with almost no influence on the existing functional features. So the "patch" does not really change the behaviour of the existing code, which makes the risk of getting a conflict small. – Doc Brown Jul 15 '14 at 18:23
  • AOP is somewhat more structured than monkey-patching. Because it relies on extra-linguistic tools, I have the assurance that only the AOP tool can modify code, and it happens at compile/startup time. In a language that allows monkey-patching, the patching can come from anywhere, at any time, depending on which statements get run. It can still be problematic - two aspects can still conflict with each other. If you want to insert some logic in between computations, a more principled way of doing it would be a [monad](http://en.wikipedia.org/wiki/Monad_%28functional_programming%29). – Doval Jul 15 '14 at 18:25
  • In JavaScript (Underscore.js in particular), it's easy to add an aspect to a function using [_.wrap](http://underscorejs.org/#wrap). Is this not be considered AOP? Why does AOP have to be more formal than that? – Mario T. Lanza Jul 15 '14 at 20:23
  • _.wrap isn't AOP if I'm reading the documentation right. Anyone with a reference to the original unwrapped function will still call it unmodified. I was referring to tools like [AspectJ](http://www.eclipse.org/aspectj/) that instrument Java bytecode. – Doval Jul 15 '14 at 21:42
  • Wrapping functions is a practice that notables in JavaScript community [liken to AOP](http://www.paulirish.com/2010/duck-punching-with-jquery/). Wrapping functions on objects and sending & modifying event messages are used to similar effect. Both intercept and act on messages. – Mario T. Lanza Jul 16 '14 at 01:26
  • @MarioT.Lanza AOP is more intrusive than that. AOP can make changes deep in the code, [violating accessibility rules](http://stackoverflow.com/questions/4402009/aspectj-and-catching-private-or-inner-methods). _.wrap can't do that because it's part of the language proper; it respects scoping rules. Wrapping a function and passing it around is something anyone can do in any language with first-class functions. AOP is about specifying patterns for changes to apply throughout the entire codebase; if you have to explicitly pass around the modified functions I wouldn't qualify that as AOP any more. – Doval Jul 16 '14 at 11:31
  • @Doval Thanks for keeping with me. I had a simplified model of AOP in mind and I'm starting to see it's something more. – Mario T. Lanza Jul 16 '14 at 12:38

1 Answers1

4

A design pattern is (to quote Wikipedia) "general reusable solution to a commonly occurring problem." You're describing a characteristic of good code, not a particular solution to a problem, so "design pattern" doesn't really apply.

I believe the concept you're looking for is cohesion. Strictly speaking, cohesion refers how well the parts of a module belong together, but if changing a single piece of functionality requires touching several different modules, then cohesion must be lacking.

Separation of concerns is a related concept.

You might also be interested in reading about monkey patching (the ability of dynamic languages to extend classes at runtime, as you're describing; usually considered a bad idea, because it can so easily cause problems) and aspect-oriented programming (a more structured approach to putting cross-cutting concerns into a single module).

Josh Kelley
  • 10,991
  • 7
  • 38
  • 50