Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Untangling the God Object (werve.net)
44 points by donw on Sept 4, 2014 | hide | past | favorite | 27 comments


I don't really understand this approach. I don't think that even in my earliest days programming Java using object-oriented principles that I would have added "search" to a Product class. After all, search is not a behavior that products perform, rather it is a property of theirs... i.e. "I am searchable". I would have most likely make some kind of ProductIndex which consisted of a hashmap or something, mapping hashes of product strings to a list of their properties for easy lookup or something... This is one thing that immediately stands out to me.

Lo and behold, you created a ProductSearcher class. It seems to me that the initial approach stems not from the view that "objects are things" but rather the notion that any related property of an object should be included in the class definition of the object, which can be summed up as a misunderstanding of object-oriented programming more so than anything else, but maybe I'm looking at this the wrong way.

Interesting article, thanks for sharing.


I've noticed that Java's tedium with millions of little files creates an instinctive knee-jerk resistance to creating new classes in new developers. Alternately, newbie C++ developers who don't have a good toolset develop a similar fear of adding classes because of concerns they'll miss something in their delicate language.

Never, ever, ever be afraid to add a class. If you've chosen an OOP language, then you have to make classes, and make them willy-nilly. Always better to create a class and then consolidate its commonalities with another class into a common base than to try and shoehorn too much logic into a single class where all its uses are intertwingled together.


In the past, when mentoring developers that tend towards god-objectery, they tended to avoid creating service objects because their mental map of the problem had a one-to-one correlation between "objects" and "the physical problem domain" (e.g., Users, Accounts, etc.)

Given how much I've seen this sort of stuff in the wild, I felt it would be a useful article to hand off to new-ish developers (I'm the author).

It sounds like you're well beyond that, though, but thanks for reading nonetheless!


In GRASP this is called "Pure Fabrication" - a thing that is not directly modeled in the problem domain. Initially, adding a search method to Product seemed sensible by using "Information Expert" (another GRASP term), but when proceeding on to adding suggestions and requiring the User object, it begins to violate "Low Coupling". You have to "fabricate" another object to avoid the God object.

http://en.wikipedia.org/wiki/GRASP_(object-oriented_design)


Sent this to a budding developer in our business. Thank you for the article. I too tend to think of objects as actors with contracts.


My pleasure -- I'm glad it helped!


I've seen this in iOS code. I think it's partly because MVC gets pushed so hard. For a new programmer, it seems as if the code has to fall in to one of those three buckets. Views and view controllers change pretty frequently so there's only one place left.


yep, that was a large problem in the early days of rails too, where everything got pushed into the model simply because it was neither a view nor a controller.


Exactly. A lot of people learn to code for practical reasons -- which is great -- and cut their teeth on a Rails or iOS app, where there are a set number of "buckets" for where code goes.

The idea of just creating other objects out of rainbow tears and unicorn dust doesn't naturally flow from this style of learning to program. :)


Amen. PHP had the same problem, and in some cases still does, but thankfully I'm seeing more and more developers (and more and more projects I'm working on here at work) where it's all Plain Old (language) Objects with some nice sprinklings of proper libraries to get stuff done. What's lovely about that is everything ends up being completely unit-testable without much extra effort. It also means I get to use proper OOP architecture yay!


Another strategy would be to use mixins: rather than think of objects as being programmed via SI classes, you instead program them as layers of functionality (mixins). Few languages have good support for mixins, however (Scala being one of them).


Mixins can be very useful, but my rule of thumb is only to use them when I'm defining a behavior. Like the conjunction rule, after I've pulled in a mixin, I should be able to say that the class is something-able.

The classic example (both for Ruby and Scala, I believe) is to use mixins to add iteration behavior to a class. This is a perfect example -- to my mind -- of where mixins really shine.

Where things get dangerous is when people start breaking objects apart into mixins because the class has gotten too big (rather than using delegation and separating concerns).

Everything is still tightly coupled together -- none of the mixins can work independently of each other, or be used by other classes. It's very difficult to test, and when a project goes crazy with this pattern, you spend a lot of time playing Hunt The Wumpus, trying to figure out exactly where behavior is defined.

I do not like Hunt the Wumpus. :)

Do keep in mind -- I've only done the tiniest amount of Scala programming, so take what I have to say with the proverbial salt-grain. But from what I understand, Scala mixins work much like Ruby mixins -- not exactly the same, but they fill a similar role.


I dislike using mixins for one off -able features...I mean, I do it, but not often. Where mixins really shine is when used in "layers" to modularize system functionality that otherwise cross cuts class boundaries. So you can take one aspect of your system...say syntax in a compiler, and separate parsing from type checking in its own layer. This an easy solution to the expression problem and compares favorably with the giant case statements favored in the functional programming community. And its quite nice: you know where functionality X of class C is, its in the C section of file X (i.e. a grid!).

Also, see virtual classes, though very few languages have first-class support for those these days.

Scala mixins (traits) are basically classes that undergo liearized multiple inheritance; they are designed to work well in a statically typed language (they can be used as constraints for type members, and they can refer to those type members themselves, leading to some nice constructions).


This blog post, 7 Patterns to Refactor Fat ActiveRecord Models[1], suggests some alternatives to mixins.

Code Climate is a pretty helpful service by the by.

[1] http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decomp...


OOP design practices often consider NounVerber classes as a design smell that should be avoided at all costs; this article introduces them as the solution for everything.

How does it go together?


That's fair criticism -- I've updated the article to make it a bit more clear.

The point isn't to create "NounVerber" classes as a solution for everything, but to break your objects apart according to the roles that they play in solving the problem.

Thinking of objects as actors has helped me with this over the years.

In the example "ProductSearcher" should probably have been named "ProductSearch" -- you can instantiate it, pass it around, and so on, so it doesn't quite behave like many the "NounVerber" objects in Javaland (e.g., AbstractFactoryBeanBuilderImpl).

When you couple this with a functional approach -- where you separate transformation and state -- magic happens. But that's a future article. :)


Maybe the objects-as-agents could pass around a struct? E.g. I imagine the Store_Manager (driver class) could call (like on the telephone) the Accountant and ask to submit a report (struct) of all the inventory that fits the parameters. Or would that be another anti-pattern?


I much prefer Noun.verb() over NounVerberFactoryInterfaceAbstractInsanityTurtleTurlteTurtleRussianNestedDollSet so this case is just missing a noun such as Catalog, so the Catalog has Products, and Catalog.search(parameters) would return a list of Products.


Coming from a JS/Mongo background rather than Rails, I was completely expecting a Collection.find() of some sort. Why should a product know how to find itself?


> NounVerberFactoryInterfaceAbstractInsanityTurtleTurlteTurtleRussianNestedDollSet

Ya, how often do you see that in OO programming?


The Java standard library has its share of such insanity.


Then it should be easy enough to provide me with an example? I've only ever seen factories with an indirection of one level in Java's standard libraries, I wouldn't be surprised if that was part of their coding style rules.

I think you would only find such monstrosities in Ecliopse.


I was curious, since I've seen this joke a lot of times, and thought surely there must be some truth to it. The longest class name I could find in the Java standard library is "SQLIntegrityConstraintViolationException". The next few longest names were also exception classes with descriptive names. The longest factory name I could find was "ContextualRenderedImageFactory", which also seems pretty reasonable.


The standard library is mostly sane; it is the enterprisey frameworks that get out of hand.

Apache XML-RPC[0]:

    RequestProcessorFactoryFactory.RequestProcessorFactory.getRequestProcessor(XmlRpcRequest)
Spring[1]: (no double-factory, but it's got all of the fun words)

    AbstractSingletonProxyFactoryBean
[0]: https://ws.apache.org/xmlrpc/apidocs/org/apache/xmlrpc/serve...

[1]: http://docs.spring.io/spring/docs/2.5.x/api/org/springframew...


What about this one:

InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState

http://javapapers.com/core-java/longest-class-method-and-att...


There are no design patterns in that name (Factory, Proxy, Singleton). Also, it sounds like the name is machine generated, which shouldn't count.


I would certainly agree that the name was clearly generated by the mechanical application of some naming rule without the application of much judgement... :-)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: