Blog

  • 2024
  • 2023
  • 2022
  • 2021
  • 2020
  • 2019
  • 2018
  • 2017
  • 2016
  • 2015
  • 2014
  • 2013
  • 2012




In the article On Names we showed that having an accurate name for domain objects is essential to provide scope and control. Now we want to concentrate on how to find names and use them consistently in our projects.

We will have a look at the language we use in our projects and provide rules how to use names in our code while adhering to naming conventions.

Ubiquitous Language

It is necessary that the technical part and the business part (i.e. domain experts) of the team use the same language. This reduces the risk of misunderstanding and helps to create a common view on the domain and the goals of the project.

Domain Driven Design

Eric Evans calls this language used by the whole team Ubiquitous Language.

The vocabulary of the UBIQUITOUS LANGUAGE includes the names of classes and prominent operations. The LANGUAGE includes terms to discuss rules that haven been made explicit in the model. It is supplemented with terms from high-level organizing principles imposed on the model [...].

Eric Evans. Domain Driven Design, p. 25

These are the steps defined by Eric Evans that lead the team to a Ubiquitous Language:

  1. Use the model as the backbone of a language.
  2. Commit the team to exercise the language relentlessly in all communication within the team and in the code.
  3. Use the same language in diagrams, writing, and especially speech.
  4. Iron out difficulties by experimenting with alternative expressions, which reflect alternative models
  5. Then refactor the code, renaming classes, methods, and modules to conform to the new model.
  6. Resolve confusion over terms in conversation, in just the way we come to agree on the meaning of ordinary words.
  7. Recognize that change in the UBIQUITOUS LANGUAGE is a change to the model.
Eric Evans. Domain Driven Design, p. 26f - reformatted to a list.

[So it is the work of the domain experts] to object to terms or structures that are awkward or inadequate to convey domain understanding; [and it is the work of developers to] watch for ambiguity or inconsistency that will trip up design.

Eric Evans. Domain Driven Design, p. 27

Glossary

One tool I find very useful to create the Ubiquitous Language is a glossary. This should be accessible to everyone in the team and everyone should in the team should be able to easily edit the terms or add additional information to it. So a technical tool like a Wiki, where each term is defined on its own page, is very handy. Tag or categorize each page as a term of the glossary so that the index of terms can be automatically created. Do not be hesitant to add information to the term that you are not quite sure of. Add it and mark it as experimental, describe why you are not sure of the term or its definition. This allows others to contribute.

In larger projects you may want to follow a more formal way. Daryl Kulak and Eamonn Guiney describe a way to create and elaborate on use cases in their book Use Cases - Requirements in Context. The process of specifying use cases has the following phases, which I interpret in the context of defining a term for the glossary:

  1. Facade - you found a term and add it with brief information to the glossary. There is no need to try to be precise or add any information at all beside its name and the context where it has been discovered.
  2. Filled - you add any information to the term you can think of. The goal is to find the whole scope for the term.
  3. Focused - you prune your findings and may add further terms to the glossary that where first thought to be part of the term, but described autonomous aspects. Remove any redundancies that where produced during the Filled Phase.
  4. Finished - polish the term, add references to related terms, contrast the term to other terms it may be confused with. Add alternative terms that are treated as synonyms, etc. The point it to integrate the term in the context of the Ubiquitous Language. Every term is now precise and coherent.

Specification by Example

Other tools to establish and use the Ubiquitous Language in your project are Agile Acceptance Testing, Specification by Example or Behaviour Driven Design (BDD). These tools help to close the communication gap between the different roles within a team (developers, product manager, domain expert, customer, tester, ...) and further ensure that the common language is used in discussions, specifications and coding. They further enforce a truly shared and consistent understanding of the domain. If you are not familiar with these kind of tools, I recommend to read one of Gojko Adzic's books: Specification by Example or Bridging the Communication Gap. Gojko Adzic also provides an interesting newsletter called Impact that provides updates on the matter.

Our testdoc-tools also help to use the project's language within tests written with JUnit. This may be an option for those that do not want to use BDD tools, but are sensitive to have readable names for test cases and generate reports to make them available to non-programmers.

At this point we have begun to establish a common language and try to consistently use the terms of our domain. Let's switch to coding and rules how to transfer this language on this very fundamental area of software projects.

Naming Software Elements

What are the rules to make up good names for your software elements?

Briefly:

The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used. 

Robert C. Martin. Clean Code

Concepts

In Chapter 2 of Clean Code, Tim Ottinger writes a lot of detailed information about Meaningful Names. He covers the following concepts:

  1. Use Intention-Revealing Names - The goal here is defined in the quote above, but since this is - in our view - the most important point, we cite it again: "The name of the variable, function, or class, should answer all the big questions. It should tell you why it exists, what is does, and how it is used." (p. 18)
  2. Avoid Disinformation - "Programmers must avoid leaving false clues that obscure the meaning of code. [...] Beware of names which vary in small ways. [...] Spelling similar concepts similarly is information. Using inconsistent spelling is disinformation." (p. 19f)
  3. Make Meaningful Distinctions - do not introduce an arbitrary name for the same concept just to distinguish two of them in a given context. Try hard to find the difference and provide meaningful name.
  4. Use Pronounceable Names - since they are part of the Ubiquitous Language each team member has to use them when they speak to each other.
  5. Use Searchable Names - if you want to search for a particular name, names like e or list are not easily searchable.
  6. Avoid Encodings - these make the domain language more complicated in the code. p_customer for a private field? IPhone for an interface for a phone? Also do not use suffixes like Impl. Name what the intention of the artifact is.
  7. Avoid Mental Mapping - do not use a meaningless name that has to be mapped to a construct of the domain by a programmer. Programmers should write code that others can easily understand.
  8. Don't Be Cute - this also takes place if a name is not taken from the Ubiquitous Language. Do not use slang or cultural dependent names. "Say what you mean. Mean what you say." (p. 26)
  9. Pick One Word per Concept - the glossary will help.
  10. Don't Pun - "[a]void using the same word for two purposes." (p. 26)
  11. Use Solution Domain Names - it is a good practice to use terms from the solution domain, like names from pattern (e.g. Factory) or common programming constructs (like Stack, Queue or List), since they reveal the intent of the structure. This terms get part of the Ubiquitous Language, if they are used outside the coders domain.
  12. Use Problem Domain Names - simply use the Ubiquitous Language.
  13. Add Meaningful Context - if you have a street and a city that is part of an address, make them elements of a class Address.
  14. Don't Add Gratuitous Context - "Shorter names are generally better than longer ones, so long as they are clear. Add no more context to a name than is necessary." (p. 30)

Rules

At the end of the book Robert C. Martin boils these advices down to seven rules to follow (Clean Code, p. 309 - 313):

  1. Choose Descriptive Names
  2. Choose Names at the Appropriate Level of Abstraction
  3. Use Standard Nomenclature Where Possible
  4. Unambiguous Names
  5. Use Long Names for Long Scopes
  6. Avoid Encodings
  7. Names Should Describe Side-Effects

I want to stress the last point of the list. If a method getInputStream not only returns a reference to an input stream, but also creates it on each call, adding the stream to the list of streams within the addressed object, the method should read addAndReturnNewInputStream. Changing the state of the addressed object has to be clear by reading the API.

The third point Use Standard Nomenclature Where Possible not only refers to the Ubiquitous Language but also carries us directly to Naming Conventions. But before we switch to this topic, we want to introduce a small tool to check the terms used in your code: tag clouds.

Tag Clouds

Tag clouds on your code help to have a view on the language actually used in your code. They also visualize the proportion of domain specific terms to technical terms.

A tool to include into your Maven build process to generate a report within your Maven Site is our tagcloud plugin.

Naming Conventions

Naming conventions are part of the project's coding conventions that make the artifacts of a team resemble the work of a single man. This uniformity is a quality attribute that helps to understand written information more easily and therefore reduces the cost of maintenance of software in particular. Naming conventions are usually influenced by the programming language used. In his book Effective Java, Joshua Bloch provides some information about naming conventions using Java.

First of all naming conventions are defined in the Java Language Specification (JLS), particularly in chapter 6.8. In his book, in Item 56: Adhere to generally accepted naming conventions (Second Edition, p. 237), Joshua Bloch divides these conventions into two categories: typographical and grammatical.

Typographical Naming Conventions

The kinds of conventions are often not controversial and easily to follow.

You should rarely violate them and never without a good reason. [... Since] violations have the potential to confuse and irritate other programmers who work with the code and can cause faulty assumptions that lead to errors.

Joshua Bloch. Effective Java, p. 237

I do not reiterate about the details on these conventions, as they are readily available on the web (JLS, 6.8). For some more details please refer to Joshua Bloch's book. Here is a table of examples for each identifier type, found on page 238, to give a short overview on these rules:

Identifier TypeExamples
Packagecom.google.inject, org.joda.time.format
Class or InterfaceTimer, FuturTask, LinkedHashMap, HttpServlet
Method or Fieldremove, ensureCapacity, getCrc
Constant FieldMAX_VALUE, NEGATIVE_INFINITY
Local Variablei, xref, houseNumber
Type ParameterT, E, K, V, X, T1, T2

Grammatical Naming Conventions

Grammatical naming conventions include rules such as classes and interfaces are named like nouns, while methods are named like verbs. Methods that return a boolean value usually start with the prefix is or has. Accessors in the context of Java Beans are prefixed with get and set, while outside this context, if no setter is provide, methods may lack this prefix for the sake of better readability.

 if(car.speed() > 2 * SPEED_LIMIT)
  generateAudibleAlert("Wacht out for cops!");

Example taken from Effective Java, p. 239.

As you can see, in opposition to typographical naming conventions, grammatical naming convention can be the source for controversial discussions. ;-)

Another set of grammatical naming conventions used in the Java API are the use of toType (as in toString) to convert an object to an independent instance of another type. asType (as in asList) to return a view on the given object with another type. There are also conventions to return a primitive Type (e.g. intValue) or to name factory methods (e.g. valueOf).

And there are many more naming conventions found in Java code. All these conventions try to reduce the need to reinvent the wheel or the risk to name the same concept differently within a project. This follows the Principle of least Astonishment and helps using an API that follows clear conventions as well as reducing maintenance costs.

Conclusion

We have shown the relevance of a Ubiquitous Language and provided information on how to establish and use it within your projects. This language has impact on three areas of a software project:

  1. reduce the communication gap within a team
  2. name elements of the domain within your code
  3. use naming conventions consistently

In the next part of this short series we will introduce the naming conventions we use in our projects.


Link

Link

Posts