One of the Best Bits of Programming Advice I ever Got
objology.blogspot.com
objology.blogspot.com
But Travis is overreacting. The REAL goal is to find a collection of abstractions that is powerful enough to accomplish what the program requires but as simple as possible (and as local as possible) to allow humans to comprehend (and maintain) it. There are quite a few times when I have found that one of these "verb-like" abstractions (a word ending in "-er") made things more comprehensible.
For example: the Gang-of-Four patterns "Builder" and "Observer" both end in "-er" and strike me as being well-named. "Builder" is an object with no purpose other than to create (initialize) another object or data structure. HAVING such an object is useful when something requires extensive setup or initialization, because it is easier to understand if the extensive initialization is kept separate from the core functionality. "Observer" is the name for an interface of things that observe... the names of interfaces FREQUENTLY work well as "verbs" since the interface frequently represents "anything that does X".
Similarly, I have often had a class such as "DatabaseConnection" and then created "DatabaseConnectionWrapper" -- a class whose purpose is to wrap a DatabaseConnection to do something like logging, error reporting, pool flushing, driver-bug-patching, and so forth. Suggestions that I call these "LoggingDatabaseConnection", "ErrorReportingDatabaseConnection" and so forth misses the key point: a different mix of features may be required at different times (eg: logging in QA but not in Prod); the fact that they are transparent wrappers that can be added (or not) in any order is a key feature of the design.
So my own advice would be weaker than Travis'. Instead of "Don't make objects that end with -er.", I would say "Be wary of confusing objects; those ending in -er are often confusing."
Following your example, you could have implemented the strategy pattern into DatabaseConnection to freely inject functionality into the object when X happens. Assuming these functions do not have additional data members other than the parent object, they easily can be simple functions or even lambdas.
(Of course it's easier to restrict to classes, because you can validate against interfaces in case a function signature doesn't cut it.)
What Travis is suggesting, when you have an object that defines both data and behavior, the object context should be determined by the data, not the behavior. If done properly, you end up with less names that end in -er.
I sometimes think human language is not enough for programmers, and there must be an easier way to create non-existing objects; maybe similar to German language word creation.
Of course, you also could be (and I was) using a deficient language like Java which doesn't HAVE any way to use a function or lambda. But I agree with you: a simple lambda a better solution where it is available.
And this kind of use is quite far from what Alan Kay intended when he designed SmallTalk. The original idea was that the objects would correspond to real-world entities. I would contend that since then OOP has evolved, and now the key idea of an object is the pairing of data and methods. Choosing the abstractions which will make the code most readable is one of the great challenges of programming well, and I find that just going for the nouns every time is NOT the best answer.
I like to think that practicing OOP in some sense is a process of defining new language and then using this language to programs something. This can be said about almost any programming in general, but in OOP you can see bad abstractions very well.
The real problem of OOP is that most "average" programmers are bad at defining languages. From my unscientific observations in any large C++ project only few developers actually produce usable class hierarchies. Same applies to large Java projects to somewhat lesser degree - Java has better defined patterns and more extensive standard library.
Why would it be any different for OOP objects? If there's an object with an internal state that chiefly responds to messages about scanning things, what's wrong with calling it NSScanner?
If the article's advice was taken, you'd end up renaming WebServer to be WebPage, but then would have nothing to name a WebPage. (Maybe WebPageSnapshot?)
what am I missing?
That it's quite possible that you don't want the guy on the other side of the wire to call those methods on the object. I find I quite frequently want to share a data model between my client and server code, but I certainly wouldn't want to expose all the stuff that the server does to those objects to the client directly.Or a Coffee-Maker... Instant factory pattern.
interface ICopyable {...}Comparable to the post's rule: in English, a few rules I've picked up are
- avoid words ending in "ly" (suffix weakens concepts; suggestion from Stephen King)
- never start a sentence with "I" and otherwise minimize its use
- "but" negates everything that came before
- avoid "to be"
Any other such suggestions, in natural or artificial languages?
[1] https://secure.wikimedia.org/wikipedia/en/wiki/Wikipedia:Neu...
http://chronicle.com/article/50-Years-of-Stupid-Grammar/2549...
Omit needless code. Omit needless code. Omit needless code.
The ~16 pages which are in fact about writing ("Toolbox") are worth more than the cover price.
My favourite crime author, by a long way. Who else can write about a killer and make him a sympathetic character.
That's easy, Donald Westlake writing as Richard Stark. Though Block is probably my favorite crime author as well.
And people so often substitute longer words, (e.g. 'myself' instead of 'me') when they want to sound professional.
"I hit myself" => OK "Please contact myself" => WRONG.
There are plenty of times to use "I" at the start of a sentence. Told by my boss "we're out of power converters", it's natural and correct to simply say/write "I will get some at Toshi station on the way in". Trying to find a sentence to say the same thing without starting with "I" is unnecessarily torturous.
I'm working on a video game at the moment, and have read lots of advice like this. My old game engine experiments all used 'Entities' to describe objects in the game world, and these 'Entities' were created, deleted and invoked by an 'EntityManager' (kind of half factory & half controller). Every game tick, the EntityManager calls a 'tick' method on all the current game entities and facilitates communication between them. For the most part, all entities are created/destroyed at the same time (game-level loading/unloading).
Trying to avoid architecture mistakes, I've come up with all sorts of tortured designs to do away with the concept of any kind of 'manager'. It is probably my inexperience with various design patterns, but all these alternatives were overly complicated and difficult to use. I would end up with a mess of objects & functors all needing pointers to each other & stepping on each others toes.
It then occurred to me that my 'manager' was in fact mapped to the real-world concept of 'a manager', being someone/something that is given orders from upper-management (game-level data, user-input, etc.) 'hires' & then assigns tasks to 'workers', hands the results to upper management, then 'fires' the workers when they are not needed ;). The metaphor works.
So I'm back to the 'manager' pattern and things are moving ahead quite nicely, even if some OO purists might frown. Should I call my 'EntityManager' 'EntityBoss'? Gets rid of the 'er' at least...
Everything is in one place, and when the systems do need to communicate it is usually in pretty well defined ways (eg. physics manager ticks--> passes collision data to entity manager which ticks--> passes scene data to render manager which draws the screen, etc)
I'll go with whatever pattern works best in the name of Just Getting Stuff Done (with my own limited brainpower).
Maybe there's another more fundamental behavior or dataset that would suggest a better name?
Perhaps Scene or World, depending on the things the EntityManager was doing. If it's reloading them it's like a scene, if it's changing gravity it's more worldy...
If I'm looking at the components of the software, and I want some code to do X, or wonder what a class Y does, what does "Controller" tell me?
If you're doing constraint verification (for example), my preference is to have a container (e.g. vector<>) of Constraint and just run find_if() to see when Constraint::Valid(environment) returns false. Then it's a class called ConstraintVerificationUtil and it has a single static method: VerifyList.
We were just discussing this yesterday: http://news.ycombinator.com/item?id=3036153.
A favorite principle: when you can't find a good name for something, it's often a sign that the concept you're trying to name isn't appropriate.
I certainly don't want event handling code all over the application just because this means I can then have noun-only classes?
My experience tells me the key aspect of software quality is the interfaces. The simpler and less leaky the interfaces, the more understandable, maintainable and correct the software will tend to be. Part of this is inherent to the problem itself, but a big chunk of it—especially in the middleware—is the ability of a software architect to have a sense of the whole project and figure out the best places to carve the interfaces. Doing so correctly is the difference between a maintainable million-line project and spaghetti. Truly brilliant engineers will figure out interfaces that make code 100x more reusable and elegant, maybe spawning open source extractions, etc.
If something is named well is an orthogonal concern, and highly contingent on what the actual object is. The best code in the world might be impossible to name intuitively if there is no real world analog.
Suspicious names: context, environment, principal, container, or manager
(all of the things google mentions, are things I've seen much, much more in Java codebase than anywhere else)(1) http://googletesting.blogspot.com/2008/11/guide-to-writing-t...
This is the full article mentioned above.
That's 4% of Sun's own JDK, not counting user defined classes. In my 15 years of Java pgmming, I've seen enterprise programmers almost always start out their OO design with a class named "xyzmanager"...probably reflecting their subliminal desire to become a manager someday :)
------ AbstractDocument.AttributeContext AbstractRegionPainter.PaintContext AbstractRegionPainter.PaintContext.CacheMode AccessControlContext AccessibleContext AppletContext BAD_CONTEXT BeanContext BeanContextChild BeanContextChildComponentProxy BeanContextChildSupport BeanContextContainerProxy BeanContextEvent BeanContextMembershipEvent BeanContextMembershipListener BeanContextProxy BeanContextServiceAvailableEvent BeanContextServiceProvider BeanContextServiceProviderBeanInfo BeanContextServiceRevokedEvent BeanContextServiceRevokedListener BeanContextServices BeanContextServicesListener BeanContextServicesSupport BeanContextServicesSupport.BCSSServiceProvider BeanContextSupport BeanContextSupport.BCSIterator CompositeContext Context Context ContextList ContextNotEmptyException ContextualRenderedImageFactory DirContext DOMCryptoContext DOMSignContext DOMValidateContext DragSourceContext DropTargetContext EndpointContext EventContext EventDirContext FontRenderContext GSSContext HttpContext InitialContext InitialContextFactory InitialContextFactoryBuilder InitialDirContext InitialLdapContext InputContext InputMethodContext JAXBContext LdapContext LogicalMessageContext LoginContext MathContext MessageContext MessageContext.Scope NamespaceContext NamingContext NamingContextExt NamingContextExtHelper NamingContextExtHolder NamingContextExtOperations NamingContextExtPOA NamingContextHelper NamingContextHolder NamingContextOperations NamingContextPOA NoContext NoContextHelper NoInitialContextException NotContextException PaintContext RenderContext ScriptContext ServiceContext ServiceContextHelper ServiceContextHolder ServiceContextListHelper ServiceContextListHolder SimpleScriptContext SOAPMessageContext SSLContext SSLContextSpi SSLSessionContext StyleContext SynthContext WebServiceContext XMLCryptoContext XMLSignContext XMLValidateContext _NamingContextExtStub _NamingContextImplBase _NamingContextStub ActivationGroupDesc.CommandEnvironment Environment GraphicsEnvironment GroupPrincipal JMXPrincipal KerberosPrincipal Principal Principal PrincipalHolder ProcessingEnvironment RoundEnvironment UserPrincipal UserPrincipalLookupService UserPrincipalNotFoundException X500Principal AdapterManagerIdHelper BeanContextContainerProxy CertPathTrustManagerParameters Container ContainerAdapter ContainerEvent ContainerListener ContainerOrderFocusTraversalPolicy CookieManager DefaultDesktopManager DefaultFocusManager DefaultKeyboardFocusManager DesktopManager DirectoryManager DomainManager DomainManagerOperations DriverManager ErrorManager FocusManager ForwardingJavaFileManager GSSManager JavaFileManager JavaFileManager.Location JComboBox.KeySelectionManager KeyboardFocusManager KeyManager KeyManagerFactory KeyManagerFactorySpi LayoutManager LayoutManager2 LogManager ManageReferralControl ManagerFactoryParameters MemoryManagerMXBean MenuContainer MenuSelectionManager NamingManager POAManager POAManagerOperations PropertyEditorManager RepaintManager RMISecurityManager RootPaneContainer ScriptEngineManager SecurityManager ServantManager ServantManagerOperations StandardJavaFileManager ToolTipManager TrustManager TrustManagerFactory TrustManagerFactorySpi UIManager UIManager.LookAndFeelInfo UndoManager ---------
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom...
In term of modeling it with objects that contain state, this may mean having objects that have a varying degree of state (unless you choose other purer approaches).
But it's naive to think that all classes should be a noun. Everything should be an abstraction that models the solution. However, nouns that end with 'er' do tend to have a little bit of state that seem unorthogonal. But I guess my point is that that's the wrong way to look at it. Better to think about it in terms of DRY. Some 'manager' or 'controller' classes violate DRY (whereas it's rare for 'connection' classes to). But not all 'manager' or 'controller' classes do.
Of course functional programming also has use cases for which it is the sweet spot solution, e.g. writing compilers.
Data deserves much more than being encapsulated in objects, data deserves the right to be put in front of the programmer so that he better sees how ill-designed his data model is :-)
You don't need state and mutations, GUIs can also be programmed nicely using functional reactive programming (FRP). A nice description of FRP:
http://stackoverflow.com/questions/1028250/what-is-functiona...
Some examples of FRP in GUIs:
main = start $ do
f <- frame [text := "Counter"]
bup <- button f [text := "Up"]
bdown <- button f [text := "Down"]
output <- staticText f []
set f [layout := margin 10 $
column 5 [widget bup, widget bdown, widget output]]
network <- compile $ do
eup <- event0 bup command
edown <- event0 bdown command
let
counter :: Discrete Int
counter = accumD 0 $ ((+1) <$ eup) `union` (subtract 1 <$ edown)
sink output [text :== show <$> counter]
actuate network
This doesn't look like good UI code to me. It seems to use too many advanced FP concepts that have nothing to do with the task at hand. Are you sure this is better than the OO approach? Why?What does good UI code look like?
It replaces a mutable counter (that could potentially be changed anywhere in the program) by a definition of the counter that describes all possible changes it can have during its lifetime:
counter = accumD 0 $ ((+1) <$ eup) `union` (subtract 1 <$ edown)
So, we have a counter that has an initial value of one. Over time, 1 can be added and 1 can be subtracted, namely when repsectively an eup or edown event occurs.Being able to capture all possible 'state mutations' of a value in one assignment is good.
It seems to use too many advanced FP concepts that have nothing to do with the task at hand.
Which is a bit ironic, since the widgets are created in the IO monad with the 'do'-notation, which simulates imperative programming in Haskell :). A user interface should be designed with a WYSIWYG interface (Glade, Qt Designer) anyway, but that's besides the point.
I think there's a duality here. If there are 20 buttons, each of which can affect some of 30 counters, then the Haskell code would say "this counter is affected by these buttons", while imperative/OO code would say "this button affects these counters". It's not obvious to me that the former way of organizing code is better.
The possible value changes in the Haskell FRP example, on the other hand, are completely described. There is no other manner in which the value can change.
Objects should have identity and can be distinguished by identity alone. They are not referentially transparent because of that. In "x = new O(); f(x,x)" you cannot substitute "new O()" into both occurrences of x.
Functional values do not have identity and you cannot tell apart 2 and 1+1. Functional values are referentially transparent. In "x = 1; y = x+x" you can change x to 1 in the definition of y.
I thought this was the best part of the essay (at least it made me smile).