The Art Of Method Names

I write from time to time on code quality and structure because it is a topic of interest to me. Clean code and well named logical structures, methods and objects really pay off during the infinitely long Support And Maintenance phase of software development.

Some could accuse me of having too many opinions on the topic, and I'd guess they could be on to something. Heck, I'll probably disagree with something I've said today, tomorrow, just because I'm always refining and learning.

While some of what I think/advocate/do is opinions, and could be subjective, I'd like to share some code I found on a project today and talk about the importance of method names.

A method should describe it's intent or behavior at the level of where it is inside the program. For example, a method named load() might be sufficiently descriptive to represent the behavior and be flexible enough to withstand a refactor or two. In other places in the program, perhaps the right method name is loadShippedOrders() since there will always be the concept of a shipped order in our proverbial system.

You get the point, right? There is a wide range of OK-ness for method names, with behavioral descriptiveness and refactorability as being two made up words that really judge the method name quality.

I found code today that really flies in the face of any of these principles. The names of these methods do not in any way describe any behavior of any system I've ever written, nor will probably be lucky enough to write.

method bodies removed to protect client interests

Be the Judge Yourself:

view plain print about
1<cfcomponent name="ET">
2 <cffunction name="phoneHome" output="yes">
3 </cffunction>
4
5 <cffunction name="createDir">
6 </cffunction>
7
8 <cffunction name="createDirImpl">
9 </cffunction>
10
11 <cffunction name="beamMeUp">
12 </cffunction>
13
14 <cffunction name="energize">
15 </cffunction>
16
17 <cffunction name="setPhaserToKill">
18 </cffunction>
19</cfcomponent>

Before you ask, this code was found in a production eCommerce system that is currently running that has nothing to do with Phasers, Energization nor beaming anything to any location.

Hard Coding Scopes In CFCs Is A No No!

Now Hear This!

This is a public service announcement. If you hard code scopes inside your CFCs (request, application, session), stop today.

I know it might be 'easier' or 'cleaner' or less lines of code, but you are really painting yourself into a corner when you do this.

An object (CFC) should not know or have access to ANYTHING outside of itself, its configuration and its immediate dependent objects.

If you want to question/argue with me on this, go for it. (Just go Read Up On Information Hiding before you do).

That Is All

I Present Making Bad Code Good To The CFMeetup March 5th @ 6:00 EST

At 6:00 EST this Thursday, March 5th, I present Making Bad Code, Good to the Online ColdFusion Meetup. You can attend this presentation virtually, by visiting the Online ColdFusion Meeting Room at 6:00 EST.

If you work on a legacy application, or on code built by lots of developers over the years, you likely laugh your way through this presentation. I promise to be thought provoking and challenge the way you write code. In this session, we'll look at lots of code samples and walk through making incremental changes to speed development, reduce errors and make life easier for everyone involved.

Ideas and concepts in this presentation will help you improve your existing applications and write more maintainable code.

The recorded presentation can be watched now!

Of Software Design, The Law of Demeter and Credit Card Companies

The Law of Demeter is a Software Engineering principle guiding how objects should talk to each other. From Wikipedia:

The Law of Demeter (LoD), or Principle of Least Knowledge, is a design guideline for developing software, particularly object-oriented programs ...[and] ...can be succinctly summarized as "Only talk to your immediate friends." The fundamental notion is that a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents).

We Don't Need No Stinking Laws

Now, I'm no fan of laws, so I privately refer to this as the General Guideline of Demeter, even though it doesn't sound as snappy or cool. However, just because there are valid reasons to break it, doesn't take away from the validity of the intent. Let's look at 2 code examples blatantly ripped off from the CFCDEV mailing list:

Conforms To Law General Guideline of Demeter

view plain print about
1Room.canCustomizeWindow()
2Room.canSelectStyle()
3Room.hasCeilingFan()

Violates Law General Guideline of Demeter

view plain print about
1Room.getPlan().canCustomizeWindow()
2Room.getPlan().canSelectStyle()
3Room.getPlan().hasCeilingFan()

Ok, So What?

In the conforming set of statements, the room is asked directly whether or not certain things can happen. The implementation (steps required to complete the task) are hidden from the calling code. This is encapsulated and will help insulate callers from changes in the implementation.

In the violating set of statements, the calling code has to get a reference to Room, then ask Room for a Plan and then query the plan. Now calling code is expected to know about this Plan and what the plan knows. This adds another level of coupling and if Plan changes, then a whole lot of code has to change as well.

However, to the programmer, the violating syntax (Room.getPlan().canSelectStyle()) could make sense. It might be that the programmer doesn't want to refactor Room and using getPlan() is a faster way to do something. If the code works, is it wrong?

I Don't Follow All This Abstract Stuff. You Are Losing Me!

Ok, fair enough. My eyes glaze over with too much abstract stuff too. Let's look at an analogy.

I made a call to a credit card company. The essence of the call was:

CC Rep: CreditCardRep.answerPhone()
Thanks for calling Law Of Demeter Credit Card Company, how may I help you?

Me: Hi, My name is Dan Wilson. I have a question as to a charge on my latest bill.

CC Rep: Hi Dan, I'm Tracy. I can help you with that. For security purposes, what is your account number, mothers maiden name and shoe size?

Me: Acct: 333-444-555-5555 mothers maiden: Stratulat Shoe Size: 9

CC Rep: CreditCardRep.verifyAccountInformation()
     Perfect. What is the charge you wish to inquire about?

Me: I have a 17.99 charge to ILovePets.com on Feb 7th. I can't find my receipt so I don't know what this is for.

CC Rep: CreditCardRep.lookUpTransaction() From the transaction details, you purchased a red dog sweater. Do you recall that purchase?

Me: (Embarassed) Yeah. ok No problem. I also wanted to change my mailing address. Can you help me with that?

CC Rep: Of course, what is the new address?

Me: 123 ColdFusion Lane, Surf City, North Carolina.

CC Rep: CreditCardRep.updateAccountAddress()
     Ok. I've updated the address. Is there anything else I can help you with?

Me: No thanks. That takes care of me.. have a nice day!

CC Rep: OK Dan. Thanks for calling Law Of Demeter Credit Card Company. Have a nice day.

What Am I Supposed To Get From That Example?

Note how I called the CC company and talked with a representative. I only spoke to that representative and was not exposed to any implementation nor had to talk to any other objects to get my tasks done. Let's look at the converse example:



CC Rep: CreditCardRep.answerPhone() Thanks for calling Demeter Violation Credit Card Company, how may I help you?

Me: Hi, My name is Dan Wilson. I have a question as to a charge on my latest bill.

CC Rep: Hi Dan, I'm Tracy. I can help you with that. For security purposes, what is your account number, mothers maiden name and shoe size?

Me: Acct: 333-444-555-5555 mothers maiden: Stratulat Shoe Size: 9

CC Rep: CreditCardRep.verifyAccountInformation()
     Perfect. I can refer you to our Payment Inquiry Department. May I place you on hold?

Me: Ummm... ok.

CC Rep: Perfect. CreditCardRep.getPaymentInquiryRep() ......

CC Rep 2: Hello, this is Jessica, the Payment Inquiry ObjectRepresentative. For security purposes, what is your account number, mothers maiden name and shoe size?

Me: (Grumbles... didn't I already say this once?) Acct: 333-444-555-5555 mothers maiden: Stratulat Shoe Size: 9

CC Rep 2: CreditCardRep.getPaymentInquiryRep().verifyAccountInformation()
     Perfect. What is the charge you wish to inquire about?

Me: I have a 17.99 charge to ILovePets.com on Feb 7th. I can't find my receipt so I don't know what this is for.

CC Rep 2: CreditCardRep.getPaymentInquiryRep().lookUpTransaction()
     From the transaction details, you purchased a red dog sweater. Do you recall that purchase?

Me: (Embarassed), yeah. ok No problem. I also wanted to change my mailing address. Can you help me with that?

CC Rep 2: No, I am sorry. Our Address Change department handles that. Would you mind if I placed you on hold?

Me: (Grumbles, looks at watch) Ummm... ok.

CC Rep 2: Perfect. CreditCardRep.getPaymentInquiryRep().getAddressChangeRep() ......

CC Rep 3: Hello, this is Ann, the Address Change ObjectRepresentative. For security purposes, what is your account number, mothers maiden name and shoe size?

Me: (Grumbles... Kicks Dog) Acct: 333-444-555-5555 mothers maiden: Stratulat Shoe Size: 9

CC Rep 3: CreditCardRep.getPaymentInquiryRep().getAddressChangeRep().verifyAccountInformation() Perfect. What is the new address?

Me: 123 ColdFusion Lane, Surf City, North Carolina.

CC Rep 3: CreditCardRep.getPaymentInquiryRep().getAddressChangeRep().updateAccountAddress()
     Ok. I've updated the address. Is there anything else I can help you with?

Me: No thanks. That takes care of me.. have a nice day!

CC Rep 3: OK Dan. Thanks for calling Demeter Violation Credit Card Company. Have a nice day.

And What Shall I Gain From That Example?

I'm sure you have had a similar experience calling a credit card company. Did you feel like their processes were well designed? Wasn't it a much cleaner experience to just deal with the main object and let it handle the implementation of getting the tasks done?

Circling back to the Law of Demeter, note this passage from Wikipedia:

When applied to object-oriented programs, the Law of Demeter can be more precisely called the "Law of Demeter for Functions/Methods" (LoD-F). In this case, an object A can request a service (call a method) of an object instance B, but object A cannot "reach through" object B to access yet another object, C, to request its services. Doing so would mean that object A implicitly requires greater knowledge of object B's internal structure. Instead, B's class should be modified if necessary so that object A can simply make the request directly of object B, and then let object B propagate the request to any relevant subcomponents. Or A should have a direct reference to object C and make the call directly. If the law is followed, only object B knows its own internal structure.
So if I am Object A, should I really be exposed to the fact that the credit card company even has a Payment Inquiry Department or an Address Change department? Surely these internal details should be kept inside the CC Company Object, not sprinkled through all the various objects that interact with a Credit Card Company.

What Should I Take Away From This Nonsensical Post?

The call dialogue examples above are contrived, I admit, but think of the above dialogues as a set of design requirements for software. Now ask yourself the following questions:

  • What would have to be updated in each of the designs if the CC company added an account verification department that validated account number, mothers maiden name and shoe size?
  • What would have to be updated in each of the designs if the CC Company merged the Payment Inquiry department with the Address Change Department?
  • Which design better encapsulates the implementation from the caller?
  • Which design incurs less ripple effect from design changes?

Thoughts, concerns, comments? Add them below!

OO Code Camp Starts This Week

In 2009, TACFUG will put on a free series of courses on Object Oriented programming in ColdFusion. We originally had slots for 20, constrained by the size of our location, and we are pretty much at capacity.

We realized this topic would have broad appeal and tried to creatively think of a way to record these sessions. Frankly, the material and the characteristics of our location does not lend itself to recording this meeting.

As a consolation prize, we will make the material used in OO Code Camp available to any other User Group that wants to use it. Just drop us a line at the TACFUG site, we'll get it over to you.

Thanks go to Alagad for sponsoring the series with Pizza. Thanks also to Doug Hughes and to Phill Nacelli for letting us use their previous OO presentations for ideas/content.