C# Encapsulation – Violation of YAGNI Principle

cencapsulation

Consider these two ways to declare a field in a C# class

option A

public class AuditController
{
    public DataAccess Service;
}

option B

public class AuditController
{
    private DataAccess service;
    public DataAccess Service { get => service; set => service = value; }
}

Which one is better? My code analyzers (sonarqube, resharper, etc) unanimously say B is better. But I disagree. I can see that B encapsulates the field, so that a person can later add validation and logging, etc. However, why not wait until you need it?

This is the YAGNI principle: you can add the getter/setter now, or wait until you need it. Since there is no penalty for waiting, you should wait. Because most likely… you ain't gonna need it.

Am I missing something?

I'm not asking whether getter/setters provide any benefit of encapsulation. I'm asking whether it is best practice to proactively add getter/setters that are doing nothing other than exposing the data.

Best Answer

There are two completely different kinds of software: libraries that need a stable binary interface across multiple versions, and applications or internal software where you can just refactor.

For internal software or applications, you are right: you can wait until something is needed, then refactor and recompile your code. So using public fields is jucky but fine.

A public[1] library doesn't have this liberty. If you change a field to a property that is a breaking change – a property is basically a method with prettier syntax. This change is source-compatible (stable API) but not binary-compatible (unstable ABI). Any dependent code that accesses this field/property has to be recompiled.

[1]: Here, “public” means “consumed by developers outside of your team”.

A lot of design advice that you see (SOLID, design patterns, …) is focused on keeping your software evolvable while still keeping ABI compatibility. This isn't bad advice, it's just not always applicable. YAGNI is the complete opposite because it assumes that the design can be fixed by refactoring. Again not bad advice, just not always applicable either.

This is not a free pass for ignoring any design advice, just a pointer that design advice tends to assume a particular context.

But even ignoring the necessity of using properties, you should always use them:

  • Properties are idiomatic C# code. Not using them makes your code more complicated to read.
  • They are not that more code to type. Deal with it.
  • Public fields in themselves are a design smell, and reek of insufficient object modeling for anything more complicated than a DTO. Properties can be publicly gettable and privately settable, which is often the better choice.
  • All databinding technologies (ASP.Net MVC Model Binding, WinForms, WFP, Xamarin, Asp.Net WebAPI, …) will only databind to properties.
  • Some cases need properties, so you might as well use them anywhere. The downsides – a tiny bit more typing, in rare cases a tiny performance hit – usually don't outweigh the increased consistency.
Related Topic