O que deve ter precedência: YAGNI ou Good Design?


76

Em que ponto a YAGNI deve ter precedência contra boas práticas de codificação e vice-versa? Estou trabalhando em um projeto no trabalho e quero lentamente introduzir bons padrões de código para meus colegas de trabalho (atualmente não há nenhum e tudo é meio que hackeado sem rima ou razão), mas depois de criar uma série de classes (nós Não faça TDD ou, infelizmente, nenhum tipo de teste de unidade. Dei um passo para trás e achei que estava violando o YAGNI porque sei com certeza que não precisamos da extensão de algumas dessas classes.

Aqui está um exemplo concreto do que quero dizer: tenho uma camada de acesso a dados que envolve um conjunto de procedimentos armazenados, que usa um padrão rudimentar de estilo de repositório com funções básicas de CRUD. Como existem vários métodos que todas as minhas classes de repositório precisam, criei uma interface genérica para meus repositórios, chamada IRepository. No entanto, criei uma interface de "marcador" (ou seja, interface que não adiciona nenhuma nova funcionalidade) para cada tipo de repositório (por exemplo ICustomerRepository) e a classe concreta implementa isso. Fiz a mesma coisa com uma implementação de fábrica para criar os objetos de negócios de DataReaders / DataSets retornados pelo Stored Procedure; a assinatura da minha classe de repositório tende a se parecer com isso:

public class CustomerRepository : ICustomerRepository
{
    ICustomerFactory factory = null;

    public CustomerRepository() : this(new CustomerFactory() { }

    public CustomerRepository(ICustomerFactory factory) {
        this.factory = factory;
    }      

    public Customer Find(int customerID)
    {
        // data access stuff here
        return factory.Build(ds.Tables[0].Rows[0]);
    }
}

Minha preocupação aqui é que eu estou violando o YAGNI porque sei com 99% de certeza que nunca haverá uma razão para dar algo que não seja concreto CustomerFactorya este repositório; como não temos testes de unidade, não preciso de MockCustomerFactorycoisas semelhantes ou semelhantes, e ter tantas interfaces pode confundir meus colegas de trabalho. Por outro lado, usar uma implementação concreta da fábrica parece um cheiro de design.

Existe uma boa maneira de chegar a um acordo entre o design adequado do software e não a arquitetura excessiva da solução? Estou questionando se preciso ter todas as "interfaces de implementação únicas" ou se posso sacrificar um pouco de bom design e apenas ter, por exemplo, a interface base e, em seguida, o concreto único, e não me preocupar com a programação para o interface, se for a implementação que será usada.


17
Você diz "como não temos testes de unidade, não preciso do MockX", o que naturalmente leva a "não preciso do IX, só preciso do X". Por outro lado, o fato de você não ter testes de unidade destaca o fato de que você precisa de IX e MockX, porque essas coisas o ajudarão a ter testes de unidade. Não aceite a realidade de não ter testes, trate-o como um problema temporário que será remediado durante (provavelmente um bom, longo) tempo.
Anthony Pegram

10
Mesmo que seja trivial para google-lo, alguém deve mencionar que YAGNI significa "yagni"
thedaian

1
Eu acho que se você estivesse escrevendo novas classes como essa, gostaria de adicionar alguns testes de unidade. Mesmo que seus colegas de trabalho não os executem. Pelo menos mais tarde, você pode dizer: "Olha! Meus testes de unidade o capturaram quando você quebrou meu código! Veja como são ótimos testes de unidade!" Nesse caso, torná-lo ridículo pode valer a pena aqui. (Embora, eu preferia que o objeto poderia ser ridicularizado sem definir uma interface)
Winston Ewert

Os testes de unidade não me forçariam a criar (ou usar) uma estrutura simulada para não atingir procedimentos armazenados ao vivo? Essa é a principal razão pela qual não costumo adicionar testes - cada um de nós tem uma cópia local do banco de dados de produção na qual testamos e escrevemos código.
Wayne Molina

3
@ Anthony E a zombaria sempre justifica a sobrecarga extra de complexidade que isso implica? A zombaria é uma ferramenta excelente, mas sua utilidade também deve ser ponderada em relação aos custos e, às vezes, a balança é inclinado para o outro lado por excesso de indireção. Claro, existem ferramentas para ajudar com a complexidade extra, mas elas não fazem com que a complexidade desapareça. Parece haver uma tendência crescente de tratar "testes a todo custo" como um dado. Eu acredito que isso é falso.
Konrad Rudolph

Respostas:


75

Existe uma boa maneira de chegar a um acordo entre o design adequado do software e não a arquitetura excessiva da solução?

YAGNI.

Eu poderia sacrificar um pouco de bom design

Falsa suposição.

e a interface de base e, em seguida, o concreto único,

Isso não é um "sacrifício". Esse é um bom design.


72
A perfeição é alcançada, não quando não há mais nada a acrescentar, mas quando não há mais nada a ser levado. Antoine De St-Exupery
Newtopian

5
@ Newtopian: as pessoas têm sentimentos confusos sobre isso em relação aos produtos mais recentes da Apple. :)
Roy Tinker

14
Eu tenho um enorme problema com esse tipo de resposta. "X é verdadeiro porque Y diz isso e Y é bem apoiado pela comunidade" raciocínio válido? Se alguém na vida real discursasse contra YAGNI, você mostraria a ele essa resposta como argumento?
vemv 17/09/11

2
@vemv. Ninguém aqui está reclamando contra YAGNI. Tudo o que S.Lott disse foi que a contradição percebida pelo OP entre dois objetivos dignos é um erro. BTW, você conhece algum desenvolvedor ativo no mundo de software de hoje que reclamaria contra a YAGNI? Se você está trabalhando em projetos reais, sabe que os requisitos mudam constantemente e que os usuários e gerentes geralmente não sabem o que fazem ou não querem até que você os coloque na frente deles. Implementar o necessário é MUITO trabalhoso - por que gastar tempo, energia e desperdiçar dinheiro (ou arriscar seu emprego) escrevendo um código que tenta prever o futuro?
Vector

6
Meu argumento não é sobre YAGNI - é sobre qualidade da resposta. Eu não digo que alguém em particular estava reclamando, era parte do meu raciocínio. Por favor, leia novamente.
vemv 17/09/11

74

Na maioria dos casos, evitar o código que você não precisará leva a um design melhor . O design mais sustentável e à prova de futuro é aquele que usa a menor quantidade de código simples e bem nomeado que atende aos requisitos.

Os projetos mais simples são os mais fáceis de evoluir. Nada mata a manutenção, como camadas de abstração inúteis e com excesso de engenharia.


8
Acho 'evitar o código YAGNI' irritantemente ambíguo. Isso pode significar um código que você não precisará ou que adere ao princípio YAGNI . (Cf. 'código KISS')
veja 16/09

2
@sehe: Não é nada ambíguo (embora "adira ao princípio YAGNI" seja totalmente contraditório) se você explicá-lo: o que "código do tipo você não precisa" pode significar, mas codificar isso? você não vai precisar?
Michael Borgwardt

1
Vou imprimir esta resposta em uma fonte grande e pendurá-la onde todos os astronautas da arquitetura possam lê-la. +1!
Kirk.burleson

1
+1. Ainda me lembro do meu primeiro projeto corporativo que me foi dado para apoiar e adicionar alguns novos recursos. A primeira coisa que fiz foi remover 32.000 linhas de código inútil de um programa de 40.000 linhas sem perder nenhuma funcionalidade. O programador original foi demitido logo depois.
EJ Brennan

4
@vemv: leia "inútil" como "atualmente não sendo usado, exceto trivialmente", isto é, um caso de YAGNI. E o "excesso de engenharia" é um pouco mais específico do que o "ruim". Especificamente, significa "complexidade causada por conceitos teóricos ou possíveis requisitos imaginados, em vez de requisitos atuais concretos".
Michael Borgwardt

62

YAGNI e SOLID (ou qualquer outra metodologia de design) não são mutuamente exclusivos. No entanto, eles são opostos quase polares. Você não precisa aderir 100% a nenhum dos dois, mas haverá algumas opções para dar e receber; quanto mais você olha para um padrão altamente abstrato usado por uma classe em um só lugar, diz YAGNI e simplifica, menos SÓLIDO o design se torna. O contrário também pode ser verdadeiro; muitas vezes no desenvolvimento, um projeto é implementado SOLIDly "na fé"; você não vê como precisará disso, mas apenas tem um palpite. Isso pode ser verdade (e é cada vez mais provável que seja verdade quanto mais experiência você ganha), mas também pode colocar você em dívidas técnicas como uma abordagem tapa-rápido; em vez de uma base de código "código espaguete" DIL, você pode acabar com "código lasanha", ter tantas camadas que simplesmente adicionar um método ou um novo campo de dados se torna um processo de vários dias para percorrer proxys de serviço e dependências fracamente acopladas com apenas uma implementação. Ou você pode acabar com o "código ravioli", que vem em pequenos pedaços pequenos que, movendo para cima, para baixo, para a esquerda ou para a direita na arquitetura, leva você a 50 métodos com 3 linhas cada.

Eu já disse isso em outras respostas, mas aqui está: Na primeira passagem, faça funcionar. No segundo passe, torne-o elegante. Na terceira passagem, torne-o SÓLIDO.

Quebrando isso:

Quando você escreve uma linha de código pela primeira vez, ela simplesmente tem que funcionar. Neste ponto, pelo que você sabe, é único. Portanto, você não recebe nenhum ponto de estilo por construir uma arquitetura "torre de marfim" para adicionar 2 e 2. Faça o que precisa e assuma que nunca mais a verá.

Na próxima vez que seu cursor entrar nessa linha de código, você já refutou sua hipótese desde a primeira vez que a escreveu. Você está revisitando esse código, provavelmente para estendê-lo ou usá-lo em outro lugar, para que não seja único. Agora, alguns princípios básicos como DRY (não se repita) e outras regras simples para o design do código devem ser implementados; extrair métodos e / ou loops de formulário para código repetido, extrair variáveis ​​para literais ou expressões comuns, talvez adicionar alguns comentários, mas, em geral, seu código deve se auto-documentar. Agora, seu código está bem organizado, se ainda estiver bem acoplado, e qualquer pessoa que o veja pode aprender facilmente o que está fazendo lendo o código, em vez de rastreá-lo linha por linha.

A terceira vez que o cursor digita esse código, provavelmente é um grande problema; você está estendendo o arquivo novamente ou ele se tornou útil em pelo menos três outros locais diferentes na base de código. Neste ponto, é um elemento-chave, se não o principal, do seu sistema e deve ser arquitetado como tal. Neste ponto, você também costuma ter o conhecimento de como ele foi usado até agora, o que permitirá que você tome boas decisões de design com relação a como arquitetar o design para otimizar esses usos e quaisquer novos. Agora as regras do SOLID devem inserir a equação; extrair classes contendo código com finalidades específicas, definir interfaces comuns para quaisquer classes que tenham finalidades ou funcionalidades semelhantes, configurar dependências fracamente acopladas entre classes e projetar as dependências para que você possa facilmente adicionar, remover ou trocar.

A partir deste momento, se você precisar estender, reimplementar ou reutilizar ainda mais esse código, tudo estará bem empacotado e abstraído no formato "black box" que todos conhecemos e amamos; conecte-o onde quer que você precise ou adicione uma nova variação no tema como uma nova implementação da interface sem precisar alterar o uso da referida interface.


Eu segundo a grandiosidade.
Filip Dupanović

2
Sim. Quando eu costumava projetar para reutilização / extensão, descobriria que, quando quisesse reutilizá-la ou estendê-la, seria de uma maneira diferente do que eu havia antecipado. A previsão é difícil, principalmente em relação ao futuro. Portanto, eu apoio a sua regra dos três ataques - a essa altura, você tem uma idéia razoável de como ela será reutilizada / estendida. Nota: uma exceção é se você já sabe como será (por exemplo, de projetos anteriores, conhecimento de domínio ou já especificado).
13ren 19/09/19

No quarto passe, torne-o INCRÍVEL.
Richard Neil Ilagan

@KeithS: Parece que John Carmack fez algo semelhante: "o código-fonte do Quake II ... unifica o Quake 1, o Quake World e o QuakeGL em uma bela arquitetura de código". fabiensanglard.net/quake2/index.php
13ren

+1 Acho que vou citar ur regra: "refactoring Prático" :)
Songo

31

Em vez de qualquer um desses, eu prefiro WTSTWCDTUAWCROT?

(Qual é a coisa mais simples que podemos fazer que é útil e que podemos lançar na quinta-feira?)

Acrônimos mais simples estão na minha lista de coisas a fazer, mas não são uma prioridade.


8
Essa sigla viola o princípio da YAGNI :)
riwalk

2
Usei exatamente as letras de que precisava - nem mais nem menos. Dessa forma, eu sou como Mozart. Sim. Eu sou o Mozart de siglas.
Mike Sherrill 'Cat Recall'

4
Eu nunca soube que Mozart era péssimo em criar siglas. Eu aprendo algo novo todos os dias em um site SE. : P
Cameron MacFarland

3
@ Mike Sherrill 'CatRecall': Talvez se deva estender isso para WTSTWCDTUWCROTAWBOF = "Qual é a coisa mais simples que podemos fazer que é útil, podemos liberar na quinta-feira e não quebrar na sexta-feira?" ;-)
Giorgio

1
@ Stargazer712 não :) viola POLA.
v.oddou

25

YAGNI e bom design não são conflitantes. YAGNI é sobre (não) apoiar necessidades futuras. Um bom design é tornar transparente o que seu software faz agora e como ele faz isso.

A introdução de uma fábrica tornará seu código existente mais simples? Caso contrário, não adicione. Se isso acontecer, por exemplo, quando você estiver adicionando testes (o que você deve fazer!), Adicione-o.

YAGNI é sobre não adicionar complexidade para suportar funções futuras.
O bom design trata da remoção da complexidade e ainda oferece suporte a todas as funções atuais.


15

Eles não estão em conflito, seus objetivos estão errados.

O que você está tentando realizar?

Você deseja escrever um software de qualidade e, para isso, manter a base de código pequena e sem problemas.

Agora chegamos a um conflito, como encobrir todos os casos se não escrevemos casos que não vamos usar?

Aqui está a aparência do seu problema.

insira a descrição da imagem aqui (qualquer pessoa interessada, isso é chamado de nuvens evaporantes )

Então, o que está dirigindo isso?

  1. Você não sabe do que não vai precisar
  2. Você não quer perder tempo e inchar seu código

Qual destes podemos resolver? Bem, parece que não querer perder tempo e inchar o código é um grande objetivo e faz sentido. E o primeiro? Podemos descobrir o que precisamos codificar?

Estou trabalhando em um projeto no trabalho e quero lentamente introduzir bons padrões de código para meus colegas de trabalho (atualmente não há nenhum e tudo é meio que hackeado sem rima ou razão) [...] dei um passo atrás e pensei que estava violando YAGNI, porque eu sei com certeza que não precisamos da extensão de algumas dessas classes.

Vamos reformular tudo isso

  • Sem padrões de código
  • Nenhum planejamento de projeto em andamento
  • Cowboys em todos os lugares fazendo suas próprias coisas (e você está tentando brincar de xerife no oeste selvagem), yee haw.

Existe uma boa maneira de chegar a um acordo entre o design adequado do software e não a arquitetura excessiva da solução?

Você não precisa de um compromisso, precisa de alguém para gerenciar a equipe que seja competente e tenha visão de todo o projeto. Você precisa de alguém que possa planejar o que você precisará, em vez de cada um de vocês colocar coisas que você NÃO precisará, porque você é incerto quanto ao futuro porque ... por quê? Vou lhe dizer por que, é porque ninguém tem um plano maldito entre todos vocês. Você está tentando introduzir padrões de código para corrigir um problema totalmente separado. Seu problema PRIMÁRIO que você precisa resolver é um roteiro e projeto claros. Depois disso, você pode dizer "os padrões de código nos ajudam a atingir esse objetivo de maneira mais eficaz como uma equipe", que é a verdade absoluta, mas está fora do escopo desta pergunta.

Obtenha um gerente de projeto / equipe que possa fazer essas coisas. Se você tiver um, precisará pedir um mapa e explicar o problema do YAGNI que não está apresentando um mapa. Se eles forem extremamente incompetentes, escreva você mesmo o plano e diga "aqui está o meu relatório sobre as coisas que precisamos, revise-o e informe-nos sua decisão".


Infelizmente não temos um. O Gerente de Desenvolvimento está mais preocupado em fazer as coisas com rapidez do que em padrões / qualidade, ou faria com que as práticas padrão como o uso de DataSets brutos em todos os lugares retornassem diretamente das classes, a codificação no estilo VB6 e tudo no code-behind com lógica duplicada copiada e colada sobre.
Wayne Molina

Tudo bem, vai ser um pouco mais lento, mas você precisa falar com as preocupações deles. Explique que esse problema do YAGNI / código inútil está perdendo tempo, sugira o roteiro, forneça a ele um roteiro, explique que isso tornará o trabalho mais rápido. Quando ele compra, entre com os problemas que os padrões pobres têm com a velocidade do desenvolvimento, sugira os melhores. Eles querem que o projeto seja concluído, eles simplesmente não sabem como gerenciar a coisa, você precisará substituí-lo ou bebê-lo ... ou sair.
Incognito

Erm ... acho que o objetivo principal seria 'você quer ter um produto bom e valioso'?
sehe

@sehe essa não é sua decisão: p.
Incognito

3
Ótima resposta. Ele está enfrentando uma batalha difícil. Fazer isso será difícil se não houver uma adesão da gerência. E você está certo de que a pergunta é prematura e não aborda o problema real.
Seth Spearman

10

Permitindo que o seu código a ser ampliada com testes de unidade é nunca vai ser coberto por YAGNI, porque você vai precisar dele. No entanto, não estou convencido de que suas alterações de design em uma interface de implementação única estejam realmente aumentando a capacidade de teste do código porque o CustomerFactory já herda de uma interface e pode ser trocado por um MockCustomerFactory a qualquer momento.


1
+1 para comentários úteis sobre o problema real, e não apenas sobre a batalha cósmica e / ou o amor entre Good Design e YAGNI.
psr

10

A questão apresenta um falso dilema. A aplicação adequada do princípio YAGNI não é algo não relacionado. É um aspecto do bom design. Cada um dos princípios do SOLID também são aspectos de bom design. Você nem sempre pode aplicar totalmente todos os princípios em qualquer disciplina. Os problemas do mundo real impõem muitas forças ao seu código, e alguns deles pressionam em direções opostas. Os princípios de design devem ser responsáveis ​​por todos esses aspectos, mas nenhum punhado de princípios pode atender a todas as situações.

Agora, vamos dar uma olhada em cada princípio com o entendimento de que, embora às vezes possam seguir direções diferentes, eles não estão inerentemente em conflito.

O YAGNI foi concebido para ajudar os desenvolvedores a evitar um tipo específico de retrabalho: o que resulta da construção da coisa errada. Isso é feito nos orientando a evitar decisões erradas muito cedo, com base em suposições ou previsões sobre o que pensamos que mudará ou será necessário no futuro. A experiência coletiva nos diz que, quando fazemos isso, geralmente estamos errados. Por exemplo, o YAGNI diria para você não criar uma interface com a finalidade de reutilização , a menos que saiba agora que precisa de vários implementadores. Da mesma forma, o YAGNI diria que não crie um "ScreenManager" para gerenciar o formulário único em um aplicativo, a menos que você saiba agora que terá mais de uma tela.

Ao contrário do que muitas pessoas pensam, o SOLID não se trata de reutilização, genericidade ou mesmo abstração. O SOLID tem como objetivo ajudá-lo a escrever o código preparado para a mudança , sem dizer nada sobre o que pode ser essa alteração específica. Os cinco princípios do SOLID criam uma estratégia para criar código flexível sem ser excessivamente genérico e simples sem ser ingênuo. A aplicação adequada do código SOLID produz classes pequenas e focadas, com papéis e limites bem definidos. O resultado prático é que, para qualquer alteração de requisitos necessária, um número mínimo de classes precisa ser tocado. E da mesma forma, para qualquer alteração de código, há uma quantidade minimizada de "ondulação" para outras classes.

Olhando para a situação de exemplo que você tem, vamos ver o que YAGNI e SOLID podem ter a dizer. Você está considerando uma interface de repositório comum devido ao fato de que todos os repositórios têm a mesma aparência do lado de fora. Mas o valor de uma interface comum e genérica é a capacidade de usar qualquer um dos implementadores sem precisar saber qual é o particular. A menos que haja algum lugar no seu aplicativo em que isso seja necessário ou útil, YAGNI diz que não faça isso.

Existem 5 princípios do SOLID a serem considerados. S é responsabilidade única. Isso não diz nada sobre a interface, mas pode dizer algo sobre suas classes concretas. Pode-se argumentar que o manuseio do acesso a dados em si pode ser uma responsabilidade de uma ou mais outras classes, enquanto a responsabilidade dos repositórios é traduzir de um contexto implícito (CustomerRepository é um repositório implicitamente para entidades do Cliente) em chamadas explícitas para o API de acesso a dados generalizada, especificando o tipo de entidade Cliente.

O é Aberto-Fechado. Isto é principalmente sobre herança. Isso se aplicaria se você estivesse tentando derivar seus repositórios de uma base comum implementando funcionalidades comuns ou se esperava derivar ainda mais dos diferentes repositórios. Mas você não é, então não.

L é substituibilidade de Liskov. Isso se aplica se você pretendeu usar os repositórios através da interface comum do repositório. Ele impõe restrições à interface e implementações para garantir consistência e evitar manuseio especial para diferentes impulsores. A razão para isso é que esse tratamento especial prejudica o objetivo de uma interface. Pode ser útil considerar esse princípio, pois pode alertá-lo para o uso da interface comum do repositório. Isso coincide com a orientação da YAGNI.

Eu sou Segregação de Interface. Isso pode ser aplicado se você começar a adicionar diferentes operações de consulta aos seus repositórios. A segregação de interface se aplica onde você pode dividir os membros de uma classe em dois subconjuntos, onde um será usado por determinados consumidores e o outro por outros, mas nenhum consumidor provavelmente usará os dois subconjuntos. A orientação é criar duas interfaces separadas, em vez de uma comum. No seu caso, é improvável que a busca e o salvamento de instâncias individuais sejam consumidos pelo mesmo código que faria consultas gerais; portanto, pode ser útil separá-las em duas interfaces.

D é injeção de dependência. Aqui voltamos ao mesmo ponto que o S. Se você separou o consumo da API de acesso a dados em um objeto separado, esse princípio diz que, em vez de apenas atualizar uma instância desse objeto, você deve transmiti-lo ao criar um repositório. Isso facilita o controle da vida útil do componente de acesso a dados, abrindo a possibilidade de compartilhar referências a ele entre seus repositórios, sem ter que seguir o caminho de torná-lo um singleton.

É importante observar que a maioria dos princípios do SOLID não se aplica necessariamente nesse estágio específico do desenvolvimento do seu aplicativo. Por exemplo, se você deve interromper o acesso aos dados depende de quão complicado é e se deseja testar a lógica do repositório sem atingir o banco de dados. Parece que isso é improvável (infelizmente, na minha opinião), então provavelmente não é necessário.

Portanto, depois de toda essa consideração, descobrimos que o YAGNI e o SOLID realmente fornecem um conselho comum e relevante imediatamente: provavelmente não é necessário criar uma interface genérica comum de repositório.

Todo esse pensamento cuidadoso é extremamente útil como um exercício de aprendizado. Consome tempo enquanto você aprende, mas com o tempo você desenvolve intuição e se torna muito rápido. Você saberá a coisa certa a fazer, mas não precisará pensar em todas essas palavras, a menos que alguém lhe peça uma explicação.


Acho que a maioria das discussões nesta página deixa de fora dois grandes concorrentes "baixo acoplamento" e "alta coesão" dos Princípios GRAS. As decisões de projeto mais caras resultam do princípio do "baixo acoplamento". Como quando "ativar" SRP + ISP + DIP por uma questão de baixo acoplamento. Exemplo: uma classe -> 3 classes no padrão MVC. Ou ainda mais caro: divida em módulos / montagens .dll / .so. Isso é muito caro por causa de implicações construção, projetos, makelists, construir servidores, arquivos de controle de versão de código-fonte adições ...
v.oddou

6

Você parece acreditar que "bom design" significa seguir algum tipo de idealogia e conjunto formal de regras que sempre devem ser aplicadas, mesmo quando inúteis.

OMI é um design ruim. YAGNI é um componente do bom design, nunca uma contradição.


2

No seu exemplo, eu diria que YAGNI deve prevalecer. Não lhe custará muito se você precisar adicionar interfaces posteriormente. A propósito, é realmente um bom design ter uma interface por classe se ela não serve a nenhum objetivo?

Mais um pensamento, às vezes o que você precisa não é um bom design, mas um design suficiente. Aqui está uma sequência muito interessante de postagens sobre o tema:


Seu primeiro e terceiro links vão para o mesmo local.
David Thornley

2

Algumas pessoas argumentam que os nomes de interface não devem começar com I. Especificamente, um motivo é que você está realmente perdendo a dependência de o tipo dado ser uma classe ou uma interface.

O que o proíbe de CustomerFactoryser uma classe no início e depois transformá-la em uma interface, que será implementada por DefaultCustormerFactoryou UberMegaHappyCustomerPowerFactory3000? A única coisa que você deve ter que mudar é o local onde a implementação é instanciada. E se você tem um design mais menos bom, esse é um punhado de lugares no máximo.

A refatoração é uma parte do desenvolvimento. É melhor ter pouco código, fácil de refatorar, do que ter uma interface e uma classe declaradas para cada classe, forçando você a alterar todos os nomes de métodos em pelo menos dois lugares ao mesmo tempo.

O ponto real no uso de interfaces é alcançar a modularidade, que é possivelmente o pilar mais importante do bom design. Observe, no entanto, que um módulo não é apenas definido por sua dissociação do mundo externo (embora seja assim que o percebemos da perspectiva externa), mas igualmente por seu trabalho interno.
O que pretendo salientar é que dissociar as coisas, que inerentemente pertencem umas às outras, não faz muito sentido. De certa forma, é como ter um armário com uma prateleira individual por copo.

A importância reside em conceber um problema grande e complexo em subproblemas menores e mais simples. E você deve parar no ponto em que elas se tornam simples o suficiente, sem subdivisões, ou então elas se tornarão mais complicadas. Isso pode ser visto como um corolário de YAGNI. E isso definitivamente significa um bom design.

O objetivo não é, de alguma forma, resolver um problema local com um único repositório e uma única fábrica. O objetivo é que essa decisão não tenha efeito no restante do seu aplicativo. É disso que trata a modularidade.
Você deseja que seus colegas de trabalho examinem seu módulo, vejam uma fachada com algumas chamadas auto-explicativas e se sintam confiantes de que eles podem usá-los, sem ter que se preocupar com todas as canalizações internas potencialmente sofisticadas.


0

Você está criando interfacevárias implementações antecipadas no futuro. Você também pode ter um I<class>para cada classe em sua base de código. Não.

Basta usar a única classe de concreto de acordo com a YAGNI. Se você achar que precisa ter um objeto "simulado" para fins de teste, transforme a classe original em uma classe abstrata com duas implementações, uma com a classe concreta original e outra com a implementação simulada.

Obviamente, você precisará atualizar todas as instanciações da classe original para instanciar a nova classe concreta. Você pode contornar isso usando um construtor estático na frente.

YAGNI diz para não escrever código antes que ele precise ser escrito.

Bom design diz usar abstração.

Você pode ter os dois. Uma classe é uma abstração.


0

Por que o marcador faz interface? Parece-me que não está fazendo nada além de "marcação". Com uma "etiqueta" diferente para cada tipo de fábrica, qual é o objetivo?

O objetivo de uma interface é dar a uma classe um "comportamento como" comportamento, dar-lhe "capacidade de repositório", por assim dizer. Portanto, se todos os seus tipos de repositórios concretos se comportarem como o mesmo IRepository (todos implementam o IRepository), todos poderão ser tratados da mesma maneira por outro código - exatamente pelo mesmo código. Nesse ponto, seu design é extensível. Adicionando tipos de repositório mais concretos, todos tratados como IRepository (s) genéricos - o mesmo código manipula todos os tipos concretos como repositórios "genéricos".

As interfaces são para lidar com coisas com base em pontos comuns. Mas as interfaces de marcador personalizadas a) não adicionam comportamento. eb) forçá-lo a lidar com sua singularidade.

Na medida em que você cria interfaces úteis, você obtém a vantagem de não precisar escrever código especializado para lidar com classes, tipos ou interfaces de marcador personalizadas que têm uma correlação de 1: 1 com classes concretas. Isso é redundância sem sentido.

De imediato, posso ver uma interface de marcador se, por exemplo, você precisar de uma coleção fortemente tipada de várias classes diferentes. Na coleção, todos são "ImarkerInterface", mas, à medida que você os puxa, você precisa convertê-los nos tipos adequados.


0

Agora você pode escrever um ICustomerRepository vagamente razoável? Por exemplo, (realmente chegando aqui, provavelmente um péssimo exemplo) no passado, seus clientes sempre usavam o PayPal? Ou todo mundo na empresa está entusiasmado com a conexão com o Alibaba? Nesse caso, você pode usar o design mais complexo agora e parecer previdente aos seus chefes. :-)

Caso contrário, espere. Adivinhar em uma interface antes de você ter uma ou duas implementações reais geralmente falha. Em outras palavras, não generalize / abstraia / use um padrão de design sofisticado até ter alguns exemplos para generalizar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.