C # campo encapsulado es una violación de YAGNI

7

Considere estas dos formas de declarar un campo en una clase C #

opción A

public class AuditController
{
    public DataAccess Service;
}

opción B

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

¿Cuál es mejor? Mis analizadores de código (sonarqube, resharper, etc.) dicen unánimemente que B es mejor. Pero no estoy de acuerdo. Puedo ver que B encapsula el campo, para que una persona pueda más tarde agregar validación y registro, etc. Sin embargo, ¿por qué no esperar hasta que lo necesite?

Este es el principio de YAGNI : puede agregar el captador / configurador ahora, o esperar hasta que lo necesite . Ya que hay sin penalización por esperar, debe esperar. Porque lo más probable ... no lo vas a necesitar.

¿Me estoy perdiendo algo?

No estoy preguntando si getter / setters proporcionan algún beneficio de encapsulación. Estoy preguntando si es la mejor práctica para agregar proactivamente adeptos / definidores que no hacen nada más que exponer los datos.

    
pregunta John Henckel 24.08.2018 - 18:28

5 respuestas

16

Hay dos tipos de software completamente diferentes: las bibliotecas que necesitan una interfaz binaria estable en varias versiones, y las aplicaciones o el software interno donde puede simplemente refactorizar.

Para el software o las aplicaciones internas, tiene razón: puede esperar hasta que se necesite algo, y luego refactorizar y recompilar su código. Así que usar campos públicos es jucky pero está bien.

Una biblioteca pública [1] no tiene esta libertad. Si cambia un campo a una propiedad que es un cambio importante, una propiedad es básicamente un método con una sintaxis más bonita. Este cambio es compatible con la fuente (API estable) pero no es compatible con binarios (inestable ABI). Cualquier código dependiente que acceda a este campo / propiedad debe ser recompilado.

[1]: aquí, "público" significa "consumido por desarrolladores fuera de tu equipo".

Una gran cantidad de consejos de diseño que usted ve (SOLIDOS, patrones de diseño, ...) está enfocado en mantener su software en evolución mientras se mantiene la compatibilidad con ABI. Este no es un mal consejo, simplemente no siempre es aplicable. YAGNI es todo lo contrario porque asume que el diseño se puede arreglar mediante refactorización. De nuevo, no es un mal consejo, pero tampoco siempre es aplicable.

Este no es un pase gratuito para ignorar cualquier consejo de diseño, solo un indicador de que el consejo de diseño tiende a asumir un contexto particular.

Pero incluso ignorando la necesidad de usar propiedades, siempre debes usarlas:

  • Las propiedades son código C # idiomático. No usarlos hace que su código sea más complicado de leer.
  • No son más código para escribir. Trata con eso.
  • Los campos públicos en sí mismos son un olor a diseño y apestan a modelado de objetos insuficientes para algo más complicado que un DTO. Las propiedades se pueden obtener públicamente y se pueden configurar de forma privada, lo que a menudo es la mejor opción.
  • Todas las tecnologías de enlace de datos (ASP.Net MVC Model Binding, WinForms, WFP, Xamarin, Asp.Net WebAPI, ...) solo se vincularán a las propiedades.
  • Algunos casos necesitan propiedades, por lo que puede usarlas en cualquier lugar. Las desventajas, un poco más de escritura, en casos raros un pequeño impacto en el rendimiento, por lo general no superan el aumento de la consistencia.
respondido por el amon 24.08.2018 - 20:01
9

YAGNI no es un principio, es una excusa para no hacer cosas.

Aquí podemos usar el azúcar sintáctico

public DataAccess Service { get; set; }

y nos costó escribir 10 caracteres para obtener los beneficios de una propiedad en un campo.

Tal vez en los viejos tiempos podría salirse con campos, pero muchas cosas esperan propiedades ahora, las va a necesitar.

Adquiera el hábito de hacer cosas por completo y no tomar atajos, y simplemente no notará el esfuerzo adicional.

    
respondido por el Ewan 24.08.2018 - 18:49
5

La validación y el registro no son realmente la razón principal para usar propiedades. ¿Con qué frecuencia los has usado para este propósito? Tengo muy raramente. Sin embargo, hay varias razones mucho más importantes para usarlas:

  • encapsulación: al tener un getter / setter, solo tiene un "punto de entrada" para acceder a su campo. Usted sabe que alguna otra pieza de código solo puede acceder al campo a través de ellos. Más tarde puede cambiar la implementación y los usuarios de la clase ni siquiera se darán cuenta. Por ejemplo, su captador puede cambiar entre devolver el valor del campo, calcular el valor sobre la marcha desde otros campos o calcularlo, pero también almacenar el valor en caché para su uso posterior. O tiene sus datos en una lista, pero luego decide que una matriz sería mejor por alguna razón. Si comienza con el acceso de campo puro, no controla cómo otro código usa ese campo y nunca puede cambiar la implementación.
  • burlón / apéndice: los accesores son métodos, por lo que pueden ser burlados por un marco de prueba, que los campos no pueden
  • permitiendo que se cambie el comportamiento en las subclases
  • ya que son métodos, pueden modificarse mediante bibliotecas de generación de código o programación orientada a aspectos; Por ejemplo, podría agregar métricas de rendimiento o control de acceso a todos los captadores que cumplan ciertos criterios utilizando un solo aspecto en AOP; su marco web o biblioteca de recursos comunes podría estar haciendo esto por usted
  • es una convención común: otros programadores esperan que uses este estilo, lo que facilita la comprensión mutua del código; a veces la consistencia es más importante que ser óptima
  • de nuevo como convención, muchos marcos pueden realizar automáticamente ciertas operaciones en clases que se ajustan al modelo de propiedad; por ejemplo, tales clases pueden asignarse automáticamente a DTO para almacenar en una base de datos, deserializarse desde y hacia JSON, etc. Algunos marcos puede funcionar de esta manera también en campos, pero otros no, por razones técnicas y convencionales.

Entonces, en realidad, hay una multa por esperar. Al no usar propiedades, pierde los beneficios mencionados anteriormente. Y como es muy difícil cambiar una vez que la versión con acceso de campo en bruto está disponible, es mejor comenzar con propiedades. El costo es mínimo, pero hay mucho que perder si necesitas alguno de los puntos anteriores más adelante.

    
respondido por el Michał Kosmulski 24.08.2018 - 19:11
3

Acabo de descubrir que en C # puedes obtener lo mejor de ambos mundos con propiedad automática . Por ejemplo,

public class AuditController
{
    public DataAccess Service { get; set; }
}

Te da la cálida sensación de encapsulación, pero sin la redundancia de opción B .

    
respondido por el John Henckel 24.08.2018 - 22:01
0

Por sí mismos, los ejemplos de código que ha proporcionado no le permiten decidir esto, porque sin el contexto (el resto del sistema, la evolución del diseño del sistema), es más o menos sin sentido hablar de los detalles de cómo encapsular, excepto vagamente, en términos de mejores prácticas.

Una buena clase OO a menudo no tendrá muchas propiedades (no habrá una asignación 1 a 1 entre la representación subyacente y la interfaz pública); en cambio, tendrá una serie de métodos que realizan alguna operación (puede pedirle al objeto que "haga algo"), y estos métodos no expondrán gran parte de lo que está sucediendo dentro del objeto.

Luego están esos "objetos" que son solo bolsas de datos, con poco o ningún comportamiento. Estos se encuentran a menudo en los límites de diferentes componentes / subsistemas. En este caso, puede decidir que los captadores y los programadores son una pérdida de tiempo, o puede decidir tenerlos por razones prácticas, según el idioma y las herramientas que esté utilizando (por ejemplo, podría facilitar la depuración).

En cuanto a YAGNI, es un principio general, no una ley del universo. Usted tiene que averiguar cuál es su dominio de aplicabilidad, y habrá algunos casos de ventaja, los beneficios de romperlo superan el costo.

    
respondido por el Filip Milovanović 24.08.2018 - 19:01

Lea otras preguntas en las etiquetas