Quanto esforço devo investir na criação de designs pouco acoplados?

10

Atualmente, estou aprendendo sobre padrões de design.

Acho que a maioria das pessoas concorda que esses padrões são ótimas ferramentas, mas devem ser usados ​​com moderação e não como resposta para tudo. Usá-los demais complicaria demais o aplicativo com pouco benefício. Os padrões devem ser usados ​​apenas onde possam ser a melhor solução ou ajudar na criação de uma boa solução (você concorda?).

Com isso em mente:

O livro que estou lendo (Head First Design Patterns) frequentemente enfatiza a importância do acoplamento solto . Esse acoplamento flexível é obtido seguindo princípios como 'programa para uma interface, não implementação' e 'encapsula o que varia'.

Basicamente, a maioria dos padrões que aprendi até agora existe principalmente para permitir que os projetos sejam fracamente acoplados e, portanto, mais flexíveis.

Entendo a importância e os benefícios do acoplamento solto.

Mas minha pergunta é: quanto esforço deve-se realmente investir na criação de projetos flexíveis e pouco acoplados?

Aqueles que se opõem aos padrões de design dizem que os custos para usá-los geralmente superam os benefícios. Você investe muito tempo na criação de um design fracamente acoplado usando algum padrão, onde , na realidade - o acoplamento flexível, 'programando em uma interface, não em uma implementação' e todos esses princípios - pode não ser tão importante.

O que eu gostaria de saber é quanto esforço devo realmente criar na criação de níveis adicionais de abstração e design, apenas para permitir que meu aplicativo siga os princípios de OO, como acoplamentos soltos, design de programa em uma interface etc. isto? Quanto esforço devo colocar nisso?

Aviv Cohn
fonte
Algumas pessoas colocam a vida inteira nisso, Kent Beck, por exemplo, pessoas que apreciam isso veriam seu esforço.
Niing 01/04/19

Respostas:

14

Resposta tola: quanto mais você faz, menos esforço é.

Basicamente, a construção de código fracamente acoplado não é realmente muito difícil. Por outro lado, treinar sua mente para pensar em termos de acoplamento flexível. E, bem, acredito que valha totalmente a pena.

Suponha que você aceite um trabalho que use uma abordagem iterativa para o desenvolvimento de software, conforme recomendado por quase todos nos últimos 20 anos. Você cria algo que funciona lindamente na iteração 1. Na iteração 2, você constrói sobre ela, adicionando novos recursos e dobrando um ou dois itens um pouco quando eles não se encaixam no conceito de iteração 1 de como as coisas devem funcionar . Agora vem a iteração 3, e você descobre que os requisitos exigem que você repense sua arquitetura básica. Como você separa seu código e o reconstrói sem voltar à estaca zero?

Isto acontece. Muito. Isso faz com que os projetos atrasem ou deixa todo mundo com muito medo de fazer o que precisa ser feito nas iterações posteriores. Na melhor das hipóteses, você recebe uma grande bola de lama. Coisas como acoplamento flexível e o princípio de responsabilidade única atenuam esses problemas em grande medida. É por isso que os princípios do SOLID são divulgados - eles realmente ajudam.

E você descobrirá que, depois de ter alguns designs fracamente acoplados, ele começa a surgir naturalmente. Padrões são coisas que as pessoas descobriram que funcionavam para eles, então eles os documentaram. São ferramentas úteis que também vêm naturalmente com o tempo.

Matthew Flynn
fonte
5

A quantidade de esforço necessária nem sempre lhe dirá o suficiente; Penso que uma medida melhor seria o esforço para a recompensa. Mas descobrir qual pode ser o retorno nem sempre é direto e sem erros.

O que deve ser lembrado dos padrões que aumentam a flexibilidade é que custa algum esforço para colocá-los, e, a menos que você possa ver exatamente por que precisa deles, pode acabar tendo a complicação no código, mas nunca usá-lo. Se a flexibilidade nunca for flexionada, é possível que ela não esteja lá.

Há uma coisa que você deve fazer sempre (ou o mais próximo possível): transformar os componentes individuais do seu software (objetos para OOP, funções para programação funcional ou processual) em caixas-pretas. Uma caixa preta é algo cujo interior (implementação) não conhecemos nem nos importamos.

Se não soubermos ou nos preocuparmos com o funcionamento, não tentaremos usar nada além da interface. Portanto, se a implementação mudar sem alterar a interface, isso só importa dentro da caixa preta - nada fora dela pode ser afetado. Isso também facilita o pensamento sobre o programa, porque você não precisa manter todos os detalhes de todo o programa em sua cabeça. Quanto mais detalhes você esquecer legitimamente, mais espaço haverá em sua cabeça para os detalhes importantes.

Eu acho que você não entendeu as objeções aos padrões de design; Não sou fã deles, mas gosto muito do princípio de acoplamento solto e programação em uma interface. Minha maior objeção a eles é que eles são apresentados como uma solução pré-empacotada que não incentiva a compreensão dos princípios por trás deles, mas sim a memorização de detalhes. Não vou recomendar que você não os estude, mas quando o fizer, lembre-se de que entender os princípios por trás deles é mais importante do que as especificidades de qualquer padrão em particular.

Uma das objeções aos padrões de design é que eles são "óbvios" ou que "eu os estava usando antes de ouvi-los, mas não com esse nome". A razão pela qual as pessoas podem fazer essas objeções, ou os criadores dos padrões de design podem criá-las em primeiro lugar, é que elas entenderam os princípios por trás delas.

O uso de caixas pretas organiza seu código de maneira sensata e geralmente não custa muito (se é que existe alguma coisa); use-os em qualquer lugar. Usar um padrão de design ou alguma outra técnica que adicione uma camada de abstração ou complique as coisas tem um custo; nunca use-as apenas porque são bonitas, arrumadas ou inteligentes; use-os quando eles se encaixam no problema e vale a pena pagar o custo para obter o benefício.

Michael Shaw
fonte
4

Sua pergunta parece equiparar o acoplamento flexível aos Design Patterns, mas eles são realmente separados, mas são coisas relacionadas.

O acoplamento frouxo é uma preocupação fundamental na programação. Assim que nos afastamos do código de máquina e entramos em linguagens simbólicas, os programas se tornam fracamente acoplados à sua execução. Etc.

OO propriamente dito é basicamente um modelo para criar componentes fracamente acoplados. O encapsulamento torna as partes internas dos objetos fracamente acopladas a outros objetos. A programação funcional talvez ainda mais, porque a execução da função é fracamente acoplada à execução de outras funções ao extremo.

Quase por definição, qualquer projeto que você faça envolverá acoplamentos frouxos. Existem várias maneiras de organizar coisas sem necessidade, mas eu só vi alguns casos em que alguém realmente projetou um sistema para ser mais bem aceito.

(De vez em quando, trabalho com alguém que deseja impedir que futuros desenvolvedores façam escolhas de design incorporando referências estáticas a artefatos de estrutura específicos, forçando seu uso - de propósito. Mas essa é realmente a exceção. e reutilizar em muitos contextos.)

Roubar
fonte
3

Os padrões devem ser usados ​​apenas onde possam ser a melhor solução ou ajudar na criação de uma boa solução (você concorda?).

Vejo padrões de design estritamente como detalhes de implementação. Se você documentar suas APIs públicas e programar para essa documentação, em geral não importará (ou afetará muito você) onde você possui padrões de design. Ou seja, você não diz "Eu tenho um padrão de ponte aqui e implementarei um visitante em cima dele". Em vez disso, é "esta classe terá implementações diferentes em vários sistemas operacionais, portanto será implementada usando um padrão de ponte". Então, quando você o usa, fica indiferente ao fato de ele ser implementado como uma ponte - porque você olha para a API pública, não um padrão de ponte.

quanto esforço se deve realmente investir na criação de projetos flexíveis e pouco acoplados?

O acoplamento frouxo pode ser alcançado seguindo um conjunto simples de regras. Se você respeitar isso, seu código será (mais) fracamente acoplado, conforme você o escrever (ou seja, qualquer esforço já faz parte do processo de desenvolvimento).

Entre as regras (não uma lista exaustiva):

  • defina suas interfaces pensando (ou escrevendo) no código do cliente (como a classe será usada), não no que a classe fará (por exemplo, desejando interface, não implementação)
  • "diga, não pergunte"
  • construir objetos a partir de peças já criadas
  • transmita ao construtor os objetos reais que você usará (não fábricas para os membros, parâmetros para as fábricas dos parâmetros ou qualquer coisa assim).
  • SECO (se você tiver duas linhas que aparecem na mesma ordem em dois lugares, extraia-as em uma função separada e assim por diante).
  • Se a criação de um objeto for uma operação mais complexa, implemente a criação das peças intermediárias como um método / classe de fábrica (ou seja, não no corpo do construtor).
  • YAGNI (crie as coisas conforme necessário, não antes).

Essas regras são seguidas de maneira diferente, dependendo do idioma, metodologia de desenvolvimento seguida por sua equipe (por exemplo, TDD), restrições de orçamento de tempo e assim por diante.

Por exemplo, em Java, é uma boa prática definir sua interface como um interfacecódigo de cliente e escrever nele (instancie a interface com uma classe de implementação).

Em C ++, por outro lado, você não possui interfaces, portanto, você pode escrever a interface apenas como uma classe base abstrata; Como no C ++ você só usa herança quando possui um requisito forte (e, como tal, evita a sobrecarga de funções virtuais desnecessárias), provavelmente não definirá a interface separadamente, apenas o cabeçalho da classe).

Aqueles que se opõem aos padrões de design dizem que os custos para usá-los geralmente superam os benefícios.

Eu acho que eles estão fazendo errado. Se você escrever um código fracamente acoplado (e DRY), a integração de padrões de design com um esforço extra mínimo. Caso contrário, você precisará adaptar seu código para implementar um padrão de design.

Se você precisar fazer muitas alterações para implementar um padrão de design, seu problema não é o padrão de design - sua base de código é monolítica e fortemente acoplada. Esse é um problema de design ruim / subótimo, não um problema de padrões de design.

O que eu gostaria de saber é quanto esforço devo realmente criar na criação de níveis adicionais de abstração e design, apenas para permitir que meu aplicativo siga os princípios de OO, como acoplamentos soltos, design de programa em uma interface etc. isto? Quanto esforço devo colocar nisso?

Suas perguntas assumem (não declaradas) que o único benefício do acoplamento flexível é a capacidade de implementar facilmente padrões de design. Não é.

Entre os benefícios do acoplamento solto estão:

  • refatoração e reformulação da flexibilidade
  • esforço menos desperdiçado
  • testabilidade
  • possibilidade aumentada de reutilizar o código
  • simplicidade de design
  • menos tempo gasto no depurador

... e alguns outros que não me vêm à cabeça agora.

utnapistim
fonte