I am working with a non-OO language and I’m trying to name my routines consistently. I came acrross the following guideline from Steve McConnell’s Code Complete:
To name a procedure, use a strong verb followed by an object
McConnell gives the following good and bad examples:
- good, non-OO –>
PrintDocument(doc)
- good, OO –>
doc.Print()
- bad, OO –>
doc.PrintDocument()
For an OO language, doc.PrintDocument()
is non-recommended on the basis that it is redundant.
I’m having a hard time wrapping my head around this guideline. Why is PrintDocument(doc)
recommended, and doc.PrintDocument()
non-recommended?
Also, what would be the problem with the simpler name Print(doc)
in a non-OO language?
Am I missing something very basic here?
1
For the non-OO situation PrintDocument()
: The suffix Document gives you the context required to know the method is to be called with a Document
parameter.
For the OO situation doc.Print()
: The doc object already gives you some context. Namely, that its methods will perform actions on a Document
. Because the context is nearly explicit it would be redundant to specify “Document” in the method name.
And wrt your second question: I’m assuming Print(doc)
isn’t recommend because it’s more difficult to discover exactly what Print
does. I guess it’s all about presenting as much information as possible as early as possible. Self documenting code!
3
The problem with questions like these is in regards to the fact that you’re talking about coding style and NOT about code itself; there’s nothing inherently wrong with this type of question (I’ve had debates with colleagues on ‘proper’ style for years), but it gets into the realm of ‘how should I name my functions to best clarify to the user what they do’ .. THAT is completely up to you the programmer. It’s completely possible to have an object (in the OO realm) that makes since to have both a Print
and PrintDocument
(maybe the Print
function handles some simple stuff for you that PrintDocument
does not, or maybe Print
prints something to the screen instead of printer). The point is that naming guidelines are just that, guidelines.
Where these kind of naming conventions really make a difference is in the procedural world (non-OO) and more specifically the C
language, which, as one user already pointed out, does not support function overloads (i.e. having 2 functions named the same but with different parameters, ex: void Print(void)
and void Print(int)
would fail in C
). In this case where the language itself inhibits you from doing such things it make since to follow some sort of convention. Also, when you’re dealing with object oriented programming, you’re usually talking about objects with state, at which point functions usually become verbs to the object (i.e. I have an Image
object, I would like to print it, so I call img.Print()
which acts on the Image
object I have .. OO and non-OO aren’t that different because the same could be said for PrintImage(Image)
), style guidelines are more about HOW the code you’re writing is conveyed to the user and that’s usually part of the ‘design’ process in the SDLC.
I’ve been in both the Linux/Unix kernels, embedded and cloud environments, Java and .NET and I have NEVER seen a single style that makes since. It ALWAYS depends on the scope of project, the team, the language, the intent and IMHO if the developer had enough sleep the night before 🙂 And while you can’t always rely on documentation, I do find that if it’s available it can give a better understanding of what a function is supposed to do than the function name itself (kernel code and API names can be VERY confusing if you’re only going off of the names).
I hope that can help
In any kind of programming, it’s helpful to have identifiers semantically divided into groups according to the kinds of things upon which they operate. In an object-oriented framework, the identifiers for different types are inherently divided into different groups regardless of what they’re called, but in a non-object-oriented framework the system lumps all identifiers together. If names don’t include something to identify what part of the program they belong to, it can be difficult to keep track of which type uses a delete
, which uses free
, which uses release
, which uses close
, which uses shutdown
, etc. while if the functions were instead named DeleteDrawingContext
, FreeMemHandle
, ReleaseLock
, CloseFile
, ShutdownSocket
, it would be much clearer. Things could be clearer yet if they used similar verbs (since one wouldn’t have to make the verbs unique to avoid naming collisions).
It’s worth noting that some people prefer to prefix identifier name with the a tag related to the subsystem that defines them (e.g. identifers related to the Foo Manager subsystem might be FM_Create, FM_Release, etc.) Such usage isn’t necessary in languages where one can logically subdivide the namespaces, but can be helpful in those where everything gets lumped together in one global namespace. Note that it doesn’t really matter if everyone follows the convention; if half the identifiers have prefixes and half don’t, the presence or absence of a prefix may become in and of itself an indication of the subsystem that defines an identifier.
If I read “Print(doc)” my first instinct would be to assume that the function that called prints the contents of doc to the console.
PrintDocument on the other hand gives the impression that the document gets actually printed by the printer.
1