LY Corporation Tech Blog

We are promoting the technology and development culture that supports the services of LY Corporation and LY Corporation Group (LINE Plus, LINE Taiwan and LINE Vietnam).

This post is also available in the following languages. Japanese

Improving code quality - Session 55: The Law of Demeter

The original article was published on January 23, 2025.

Hello, I'm Munetoshi Ishikawa, a mobile client developer for the LINE messaging app.

This article is the latest installment of our weekly series "Improving code quality". For more information about the Weekly Report, please see the first article.

The Law of Demeter

One of the programming principles is the Law of Demeter. This principle states that you should only operate on members (properties/methods) that you directly know, and you should not operate on "members of members". In other words, it is often described as "only talk to your friends". More precisely, when accessing members, the receiver (in many languages, the value to the left of the dot operator .) should be limited to the following:

  • this
  • Fields/properties of this
  • Function arguments
  • Objects created directly within the function
  • Top-level/global values or singletons

In practice, function calls without a receiver can also be considered to follow the Law of Demeter.

Below is an example that follows the Law of Demeter.

val TOP_LEVEL_VALUE = ... 

class Klass {
    val property: Property = ...

    fun thisFunction() { ... }

    fun function(parameter: Parameter) {
        // OK: Function with `this` as the receiver
        thisFunction()

        // OK: Member with `this` as the receiver
        property.prop

        // OK: Function argument as the receiver
        parameter.func()

        // OK: Object created directly within the function as the receiver
        Value(42).prop

        // OK: Top-level variable as the receiver
        TOP_LEVEL_VALUE.func()
    }
}

On the other hand, the following code does not follow the Law of Demeter.

class Klass {
    val property: Property = ...

    fun function(parameter: Parameter) {
        // Bad: Receiver is the return value of a property method
        property.func().prop

        // Bad: Receiver is a property of an argument
        val prop = parameter.prop
        prop.anotherProp
    }
}

Consider the following code. In this code, the receiver of filter is the return value of getAllUserModels, so it does not follow the Law of Demeter.

class Caller {
    val repository: UserModelRepository = ...

    fun function() {
        val friendModels = repository.getAllUserModels()
            .filter { it.isFriend }

        ...
    }
}

Therefore, a developer thought it would be better to follow the Law of Demeter and refactored it as follows.

class Caller {
    val repository: UserModelRepository = ...

    fun function() {
        val friendModels =
            filterFriends(repository.getAllUserModels())

        ...
    }

    fun filterFriends(allUserModels: List<UserModel>): List<UserModel> =
        allUserModels.filter { it.isFriend }
}

Is there any problem with this "refactoring"?

In a nutshell

Instead of superficially applying the Law of Demeter, be aware of the boundaries of knowledge.

Keywords: Law of Demeter, information hiding, encapsulation

List of articles on techniques for improving code quality