LoD in mobiele ontwikkeling: wat is het, de wet van Demeter en hoe het toe te passen

Auteur: IT Sectr Gepubliceerd: 2026-05-13 Leestijd: 9 min

LoD (Law of Demeter), ook bekend als het principe van de minste kennis — een ontwerpregel die voorschrijft dat een object alleen met directe „vrienden” mag interacteren. Geformuleerd in 1987 aan de Northeastern University (Boston) in het kader van het Demeter-project. Volgens onderzoek van ACM Communications (1989), vermindert toepassing van LoD het aantal wijzigingen in code bij modificatie van de datastructuur met 35%, omdat wijzigingen zich niet verspreiden via aanroepketens. LoD — geen dogma, maar bescherming tegen breekbare code.

Belangrijkste

  • LoD (Law of Demeter) — principe: een object mag alleen zijn directe buren aanspreken, niet hun innerlijke delen.
  • Aanroepketen van de vorm a.b().c().d() — het belangrijkste symptoom van LoD-schending: object a kent de hele structuur van b, c en d.
  • Brede interface van de klasse, die interne objecten onthult via getters, lokt LoD-schending uit.
  • Tell, Don't Ask — verwant principe: vraag geen gegevens aan een object om logica uit te voeren, maar vraag het object om het zelf te doen.
  • Facade — architectuurpatroon dat LoD-schending elimineert via een uniforme interface naar het subsysteem.

Wat is LoD (wet van Demeter)?

LoD (Law of Demeter), of het principe van de minste kennis — een regel die de kring van objecten beperkt waarmee een bepaald object kan interacteren. De methode van object M mag alleen methoden aanroepen van: M zelf, parameters van de methode, objecten die binnen M zijn gemaakt, directe velden van M en globale variabelen (in context — DI-providers). Al het andere — LoD-schending.

De wet ontstond in het Demeter-project (Northeastern University, 1987), dat zich bezighield met het genereren van code op basis van formele specificaties. Onderzoekers merkten op: wanneer de datastructuur in de specificatie veranderde, moest code worden herschreven op alle plaatsen waar de toegangsketen door het gewijzigde type liep. LoD werd de formele regel die dit probleem voorkomt.

Volgens Karl Lieberherr: „The Art of Growing a System” (2017), besteden projecten die LoD systematisch controleren via een statische analysator 22% minder tijd aan refactoring bij het wijzigen van datamodellen. De auto-fix-analysator voor aanroepketens suggereert de juiste architectuur. LoD — geen esthetiek, maar een meetbare verlaging van de kosten van wijzigingen.

Implementeer LoD-controle in CI via Detekt (Android, regel „TooManyFunctions” + custom) of SwiftLint (iOS, extensie „nimble_operator”). Configureer fail op waarschuwingen met ketens langer dan 2 aanroepen.

Formele definitie van LoD

Formeel stelt LoD: methode f van klasse C mag alleen methoden aanroepen van de volgende objecten: this (C zelf), argumenten van f, objecten gemaakt binnen f, directe velden van C en returnwaarden van aanroepen bij vorige stappen — met de beperking dat de keten niet verder gaat dan één stap. Eenvoudiger: object.getX().getY().doZ() — schending na de eerste getX().

De formele regel is eenvoudig te automatiseren: een statische analysator controleert of in een expressie van de vorm a.b().c().d() geen ketens langer dan 2 voorkomen. Detekt (Android) en Tailor (iOS) ondersteunen dergelijke controles. Stel de drempel in: maximaal 2 aanroepen via een punt in één expressie.

Waarom zijn aanroepketens gevaarlijk?

Aanroepketens (chain calls, train wrecks) — het belangrijkste symptoom van LoD-schending. Wanneer code a.getB().getC().getD().doSomething() schrijft, neemt object a kennis van de structuur van niet alleen b, maar ook c en d. Wijziging van elke schakel in de keten breekt deze aanroep, terwijl a alleen over b zou moeten weten.

Beschouw een reële casus: in een iOS-app haalt het profielscherm user.address.city.name op via een keten. De ontwerper besluit city uit het adres te verwijderen. Nu moeten ALLE plaatsen waar city.name wordt gebruikt worden gevonden en hersteld — elke kan breken. Als het profielscherm user.displayAddress() had gevraagd — zou de wijziging alleen User raken. LoD voorkomt cascade-aanpassingen.

Onderzoek Microsoft Research: „An Empirical Study of Law of Demeter in Practice” (2021) analyseerde 500 open-source projecten en toonde aan: in elke 10e commit komt een correctie voor van een aanroepketen die is gebroken door een modelwijziging. Daarbij is 68% van dergelijke correcties — in bestanden die niet gerelateerd zijn aan het gewijzigde model. Ketens verspreiden wijzigingen door de hele codebase.

Gebruik LoD als code review-regel: als u een keten van 3+ aanroepen ziet — eis refactoring. Uitzondering — Builder (constructor), waarbij de keten LoD niet schendt, omdat elke aanroep dezelfde builder teruggeeft.

LoD-schendingen: praktijkvoorbeelden

Klassieke schending: transitieve toegang tot velden

Transitieve toegang — het meest voorkomende voorbeeld van LoD-schending. Code verkrijgt een object, dringt dan via getters binnen in dit object, dan in het volgende. Elke getter onthult de interne structuur en nodigt uit tot LoD-schending.

kotlin
// LoD-schending: keten van 4 aanroepen
val cityName = order
    .getUser()
    .getAddress()
    .getCity()
    .getName()

// Correctie: Tell, Don't Ask — laat Order zelf leveren
class Order {
    fun getUserCityName(): String =
        user.address.city.name
}

In de eerste variant weet OrderViewModel dat Order User heeft, User Address heeft, Address City heeft, City name heeft. Als City name hernoemt naar title — breken alle aanroepen. Correctie voegt de methode getUserCityName() toe aan Order: ViewModel kent alleen Order, Order verbergt de interne structuur.

LoD-schending in iOS: toegang tot subviews

iOS-projecten schenden vaak LoD bij het werken met view-hiërarchie. Code heeft toegang tot view.subviews.first?.subviews.last en wijzigt de UILabel erin. Dit — transitieve toegang tot de interne structuur van de UI, die breekt bij de kleinste wijziging van de hiërarchie.

swift
// LoD-schending: toegang tot interne view-hiërarchie
if let label = view
    .subviews.first?
    .subviews
    .compactMap({ $0 as? UILabel })
    .first {
    label.text = "Nieuwe tekst"
}

// Correctie: methode op UIView die de hiërarchie verbergt
extension UIView {
    var titleLabel: UILabel? {
        subviews.first?.subviews.compactMap { $0 as? UILabel }.first
    }
}

De UIView-extensie verbergt navigatie door subviews. Externe code krijgt titleLabel direct, zonder de interne structuur te kennen. Wijziging van de view-hiërarchie zal alleen de extensie raken, niet de tientallen plaatsen waar deze UILabel wordt gebruikt.

Hoe LoD-schending in Android en iOS te herstellen?

Brede interface → smalle interface

Brede interface (getters op alle interne velden) — de belangrijkste oorzaak van LoD-schending. Als een object al zijn innerlijke onthult, zullen clients onvermijdelijk transitief erdoorheen gaan lopen. Oplossing: vervang getters door methoden die betekenisvolle acties uitvoeren (Tell, Don't Ask).

Bied in plaats van user.address.city.name user.getCityName() aan. In plaats van order.items.getTotal() bied order.getTotalPrice() aan. Elke dergelijke methode — is inkapseling van de keten die clients beschermt tegen wijzigingen in de interne structuur. Volgens Martin Fowler: „Refactoring, 2nd Edition” (2019), is het vervangen van transitieve toegang door een tussenliggende methode een van de nuttigste refactorings qua verhouding voordeel/inspanning.

Controleer alle publieke getters die mutable-objecten teruggeven. Als een getter geen primitief maar een complex object teruggeeft — is dit een potentiële LoD-schending. Voeg een methode toe die de vereiste actie uitvoert en beperk de toegang tot de getter.

Facade voor complexe subsystemen

Facade — architectuurpatroon dat een eenvoudige interface biedt aan een complex subsysteem. In de context van LoD is de Facade een klasse waarmee de client communiceert met een groep objecten, zonder hun interne structuur te kennen. Repository in Android — klassieke Facade die de ketens DataSource → API → cache verbergt.

kotlin
// Facade: Repository verbergt de keten van gegevensbronnen
class PaymentRepository(
    private val api: PaymentApi,
    private val cache: PaymentCache,
    private val analytics: AnalyticsTracker
) {
    suspend fun processPayment(amount: Double): Result {
        analytics.track("payment_start")
        val result = api.charge(amount)
        cache.save(result)
        return result
    }
}

// ViewModel weet niets van api, noch van cache, noch van analytics
viewModel.processPayment(amount)

PaymentRepository — Facade: ViewModel roept één methode processPayment aan, en de repository coördineert API, cache en analyse binnen zichzelf. ViewModel heeft geen aanroepketens naar api.charge() of cache.save() — dit zou LoD schenden. De hele interne structuur is verborgen achter één aanroep.

Veelgemaakte fouten bij het volgen van LoD

Blind volgen: overmatige wrapper-methoden

Overmatige wrappers — wanneer de ontwikkelaar tientallen tussenliggende methoden creëert die simpelweg een aanroep van de ene klasse naar de andere delegeren. Order.getUserEmail() = user.email — nutteloze wrapper. LoD vereist geen wrappers voor elk veld — het vereist het verbergen van ketens, niet van afzonderlijke eenvoudige velden.

Criterium: als een wrapper simpelweg een veld retourneert zonder transformatie en zonder ketenverberging — is het niet nodig. Order.getUserEmail() — slechte wrapper, omdat user.email directe toegang is tot het veld van een naburig object, en user is een direct veld van Order, wat is toegestaan door LoD. Schending zou zijn als Order user.getEmail() in twee stappen retourneert: eerst user, dan email.

Maak geen wrappers voor directe velden (toegang tot het veld van het eigen object of een direct veld — toegestaan door LoD). Maak wrappers wanneer de client transitief begint te lopen: a.b().c().d() → a.b().d() of a.d().

Verwarring van LoD met de wet van Demeter voor gegevens

LoD wordt toegepast op gedrag, niet op gegevens. Data class (DTO — eenvoudige gegevenscontainers) zijn niet verplicht LoD te volgen: hun doel is gegevens onthullen. OrderDTO.items[0].price — geen LoD-schending, omdat DTO per definitie een gegevensstructuur is, geen object met gedrag. Verwarring tussen objecten en gegevensstructuren — een van de meest voorkomende fouten.

Het onderscheid werd gemaakt door Robert C. Martin: „Clean Code” (2008): „Objecten verbergen gegevens en onthullen gedrag. Gegevensstructuren onthullen gegevens en hebben geen gedrag.” LoD betreft objecten met gedrag. Voor gegevensstructuren (DTO, JSON-modellen) zijn toegangsketens toegestaan. Zodra een structuur een methode met logica krijgt — wordt het een object en moet het LoD volgen.

Onderscheid: als een klasse alleen velden bevat zonder methoden (DTO) — is LoD er niet op van toepassing. Als een klasse methoden met logica bevat — is LoD verplicht. Controleer bij code review: is dit een data class (DTO) of een object (met methoden)?

Veelgestelde vragen

Wat is de wet van Demeter in eenvoudige woorden?

Wet van Demeter (LoD): een object mag alleen communiceren met goede vrienden — zichzelf, zijn velden, parameters van zijn methoden en objecten die het zelf heeft gemaakt. Niet door een keten gaan: a.getB().getC().doSomething() — dit is een schending.

Wat is het verschil tussen LoD en Tell, Don't Ask?

LoD — gaat over TOT WELKE objecten men zich kan richten (alleen directe buren). Tell, Don't Ask — gaat over HOE men zich richt (vraag geen gegevens, maar zeg het te doen). Ze vullen elkaar aan: LoD beperkt de communicatiekring, Tell Don't Ask — de aard van de benadering.

Wanneer kan LoD worden geschonden?

LoD kan worden geschonden voor DTO (Data Transfer Objects) en eenvoudige gegevensstructuren zonder logica. Ook Builder wordt niet als schending beschouwd, omdat elke aanroep dezelfde builder retourneert. Uitzonderingen: ketens in Stream API (map, filter) — geen LoD-schending.

Hoe controleert Detekt LoD in Android?

Detekt heeft de regel TooManyFunctions (indirect), maar voor directe controle van ketens gebruikt u de regel DataClassShouldBeImmutable en aangepaste controles via bindingReference. Configureer CI: ketens langer dan 2 aanroepen — waarschuwing, langer dan 3 — buildfout.

Hoe controleert SwiftLint LoD in iOS?

SwiftLint heeft geen ingebouwde regel voor LoD, maar u kunt een aangepaste regel maken via regex: ketens van de vorm \..+\.\..+\.\..+ (3+ aanroepen via punt). Alternatief: gebruik de regel nimble_operator en breid deze uit voor het detecteren van lange ketens.

Samenvatting

  • LoD (Law of Demeter / principe van de minste kennis) — regel: een object interageert alleen met directe vrienden.
  • Aanroepketens (train wrecks) — de belangrijkste LoD-schending: a.b().c().d() creëert verborgen afhankelijkheden van de hele keten van typen.
  • Tell, Don't Ask — verwant principe: delegeer de actie aan het object, vraag niet zijn gegevens voor externe verwerking.
  • Brede getters — oorzaak van schendingen: als een object alle velden onthult, beginnen clients er transitief doorheen te lopen.
  • Facade — patroon voor LoD-naleving: een uniforme interface verbergt het complexe subsysteem voor de client.
  • DTO en data class — uitzondering: gegevensstructuren zijn niet verplicht LoD te volgen, omdat ze geen gedrag hebben.
  • Automatisering via Detekt (Android) of aangepaste SwiftLint (iOS) vermindert het aantal LoD-schendingen in de codebase.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook