Uma maneira de entender isso é imaginar possíveis mudanças de requisitos em projetos futuros e se perguntar o que você precisará fazer para que isso aconteça.
Por exemplo:
New business requirement: Users located in California get a special discount.
Example of "good" change: I need to modify code in a class that computes discounts.
Example of bad changes: I need to modify code in the User class, and that change will have a cascading effect on other classes that use the User class, including classes that have nothing to do with discounts, e.g. enrollment, enumeration, and management.
Ou:
New nonfunctional requirement: We'll start using Oracle instead of SQL Server
Example of good change: Just need to modify a single class in the data access layer that determines how to persist the data in the DTOs.
Bad change: I need to modify all of my business layer classes because they contain SQL Server-specific logic.
A ideia é minimizar a pegada de futuras mudanças potenciais, restringindo modificações de código a uma área de código por área de mudança.
No mínimo, suas aulas devem separar preocupações lógicas de preocupações físicas. Um grande conjunto de exemplos pode ser encontrado no namespace System.IO
: lá podemos encontrar vários tipos de fluxos físicos (por exemplo, FileStream
, MemoryStream
ou NetworkStream
) e vários leitores e gravadores ( BinaryWriter
, TextWriter
) que funcionam em um nível lógico. Ao separá-los dessa maneira, evitamos explosão combinatória: em vez de precisar de FileStreamTextWriter
, FileStreamBinaryWriter
, NetworkStreamTextWriter
, NetworkStreamBinaryWriter
, MemoryStreamTextWriter
e MemoryStreamBinaryWriter
, basta conectar o gravador e o fluxo e você pode ter o que você quer. Então, mais tarde, podemos adicionar, digamos, um XmlWriter
, sem precisar reimplementá-lo para memória, arquivo e rede separadamente.