Estou trabalhando em um projeto grande (para mim), que terá muitas aulas e precisará ser extensível, mas não tenho certeza de como planejar meu programa e como as classes precisam interagir.
Fiz um curso de OOD há alguns semestres e aprendi muito com ele; como escrever UML e traduzir documentos de requisitos em objetos e classes. Também aprendemos diagramas de sequência, mas de alguma forma eu perdi a palestra ou algo assim, eles realmente não ficaram comigo.
Em projetos anteriores, tentei usar os métodos que aprendi no curso, mas geralmente termino com um código que, assim que posso dizer "sim, parece algo com o que eu tinha em mente", não tenho vontade de vasculhar a sujeira para adicionar Novas características.
Eu tenho uma cópia do Code Complete de Steve McConnell que eu sempre ouço é incrível, aqui e em outros lugares. Eu li o capítulo sobre design e não parecia ter as informações que estou procurando. Eu sei que ele diz que não é um processo de corte e secagem, que é principalmente baseado em heurísticas, mas não consigo pegar todas as informações dele e aplicá-las aos meus projetos.
Então, o que você faz durante a fase de design de alto nível (antes de começar a programar) para determinar quais são as classes de que você precisa (especialmente as que não são baseadas em nenhum 'objeto do mundo real') e como elas irão interagir umas com as outras ?
Especificamente, estou interessado em quais são os métodos que você usa? Qual é o processo que você segue que geralmente produz um design bom e limpo que representará de perto o produto final?
fonte
Respostas:
As etapas que eu uso para o design inicial (como chegar a um diagrama de classes) são:
Levantamento de requisitos. Converse com o cliente e considere os casos de uso para definir qual funcionalidade o software deve ter.
Componha uma narrativa dos casos de uso individuais.
Percorra a narrativa e destaque substantivos (pessoa, local, coisa), como classes candidatas e verbos (ações), como métodos / comportamentos.
Descarte substantivos duplicados e considere a funcionalidade comum.
Crie um diagrama de classes. Se você é um desenvolvedor Java, o NetBeans 6.7 da Sun possui um módulo UML que permite diagramação, engenharia de ida e volta e é GRATUITO. O Eclipse (um IDE Java de código aberto) também possui uma estrutura de modelagem, mas não tenho experiência com ela. Você também pode experimentar o ArgoUML, uma ferramenta de código aberto.
Aplique os princípios de OOD para organizar suas aulas (fatorar funcionalidades comuns, construir hierarquias etc.)
fonte
Adicionando o que Scott Davies tinha a dizer:
Certifique-se de que você sabe o que é o seu programa antes de começar. Qual é o seu programa? O que isso não fará? Que problema ele está tentando resolver?
Seu primeiro conjunto de casos de uso não deve ser uma lista completa de tudo o que o programa fará eventualmente. Comece com o menor conjunto de casos de uso possíveis, que ainda captura a essência da finalidade do seu programa. Para este site, por exemplo, os principais casos de uso podem ser fazer login , fazer uma pergunta , responder a uma pergunta e visualizar perguntas e respostas . Nada sobre reputação, votação ou wiki da comunidade, apenas a essência do que você está procurando.
Ao criar classes potenciais, não pense nelas apenas em termos de qual substantivo elas representam, mas de quais responsabilidades elas têm. Eu descobri que essa é a maior ajuda para descobrir como as classes se relacionam durante a execução do programa. É fácil criar relacionamentos como "um cachorro é um animal" ou "um filhote tem uma mãe". Geralmente é mais difícil descobrir relacionamentos que descrevem interações em tempo de execução entre objetos. Os algoritmos do seu programa são pelo menos tão importantes quanto os seus objetos e são muito mais fáceis de projetar se você tiver explicado qual é o trabalho de cada classe.
Depois de obter esse conjunto mínimo de casos de uso e objetos, comece a codificar. Consiga algo que realmente corra o mais rápido possível, mesmo que não faça muito e provavelmente pareça uma porcaria. É um ponto de partida e forçará você a responder perguntas que você pode encobrir no papel.
Agora volte e escolha mais casos de uso, escreva como eles funcionarão, modifique seu modelo de classe e escreva mais código. Assim como seu primeiro corte, faça o mínimo de cada vez que puder, acrescentando algo significativo. Enxague e repita.
Apenas meus dois centavos. Espero que seja útil.
fonte
Quando tive a chance, normalmente uso o que chamo de "regra das três iterações".
Na primeira iteração (ou inicialização), desenvolvo o layout geral do aplicativo de acordo com os objetos de modelo, os algoritmos e o esperado ( realmente esperado, não talvezesperado) direções futuras. Não escrevo documentos de design, mas se for necessário coordenar várias pessoas, é claro que é necessário um esboço do procedimento, juntamente com uma análise das dependências e estimativa do tempo necessário. Tente manter essa fase no mínimo se, como eu, você preferir um método mais ágil. Há casos em que é necessária uma fase de design forte, principalmente quando tudo é conhecido e verdadeiro sobre a lógica do seu programa e se você planeja ter muitas interações entre os recursos do seu código. Nesse caso, os casos de uso ou histórias de usuário fornecidos são uma boa ideia de alto nível, principalmente para aplicativos de GUI. Para aplicativos de linha de comando e, em particular, bibliotecas, tente escrever "histórias do programa" nas quais você codifica contra a biblioteca que precisa desenvolver e verifique como fica.
Após essa primeira iteração, você entenderá melhor como as coisas interagem, descobriu os detalhes e os pontos difíceis, resolveu os problemas com um adesivo de fita adesiva. Você está pronto para usar essa experiência para melhorar, limpar, polir, dividir o que era muito grande, unir o que era muito fragmentado, definir e usar padrões de design, analisar gargalos de desempenho e problemas de segurança não triviais. Em geral, todas essas alterações terão um enorme impacto nos testes de unidade que você escreveu, mas não nos testes funcionais.
Ao concluir esta segunda iteração, você terá uma pequena jóia, bem testada, bem documentada e bem projetada. Agora você tem a experiência e o código para executar a terceira iteração, estenda. Você adicionará novos recursos e casos de uso para melhorar seu aplicativo. Você encontrará pontos difíceis e acabará inserindo uma quarta iteração, que é análoga à segunda. Enxague e repita.
Essa é minha abordagem geral ao design de software. É semelhante ao design espiral, com curtas iterações de três meses e elementos de desenvolvimento Agile, que permitem aprender os problemas e conhecer seu software e seu campo de aplicação. Obviamente, é uma questão de escalabilidade; portanto, se o aplicativo é tão grande para envolver centenas de desenvolvedores, as coisas são um pouco mais complexas do que isso, mas no final, acho que a ideia é sempre a mesma, divide et impera .
Então resumindo:
fonte
A fonte mais interessante que conheço sobre isso é a Parte D da Construção de Software Orientada a Objetos, 2ª Edição de Bertrand Meyer.
Parte D: Metodologia orientada a objetos: aplicando bem o método
19: Na metodologia, 20: Padrão de projeto: sistemas interativos com vários painéis, 21: Estudo de caso de herança: "desfazer" em um sistema interativo, 22: Como encontrar as classes , 23: Princípios de design de classe, 24: Usando bem a herança , 25: Técnicas úteis, 26: Um senso de estilo, 27: Análise orientada a objetos, 28: O processo de construção de software, 29: Ensinando o método
Curiosamente, o capítulo 22. Como encontrar as aulas está disponível online.
fonte
É frequentemente repetido, mas completamente verdadeiro - entenda seus dados.
Para OOP, suas aulas devem descrever informações importantes e como elas interagem.
Se você tiver um modelo mental que descreva bem o comportamento e a vida útil dos dados, será fácil explicar suas aulas.
Isso é simplesmente uma extensão de: Saiba exatamente o que você está tentando fazer.
fonte
Tente usar o desenvolvimento orientado pelo comportamento. Vai ser difícil quebrar seus velhos hábitos, mas descobri que o BDD é realmente a sua melhor aposta quando se trata de se desenvolver no mundo real.
http://behaviour-driven.org/
fonte
O problema com grandes projetos é que você não pode supervisionar todas as interações entre componentes. Portanto, é importante reduzir a complexidade do projeto. Os diagramas de classe e sequência são muito detalhados para esta fase do design.
Primeiro tente pensar em um nível de abstração mais alto. Pense nos principais componentes e em suas responsabilidades (sua interface com outros componentes), observe alguns padrões de arquitetura em busca de inspiração (não, não padrões de design, esses são níveis muito baixos! MVC e Multi-Tier são exemplos de padrões arquiteturais). Para projetos razoavelmente grandes, essa visão deve ter cerca de 3-5 componentes.
Somente então você amplia um determinado componente e tenta projetá-lo. Agora estamos no nível de padrões de design e diagramas de classes. Tente se concentrar nessa parte do projeto, se achar que precisa adicionar uma responsabilidade a um dos outros componentes, basta adicioná-lo à sua documentação / lista de tarefas. Não perca tempo pensando nas implicações, neste ponto, elas mudam muito rapidamente, revise quando o design for mais sólido.
Você não precisa projetar completamente cada componente neste momento, embora seja provavelmente bom ter um pedaço de código que implemente a interface de componentes não implementados e gere respostas simples, mas úteis. Dessa forma, você pode iniciar o desenvolvimento (e o design) de um componente por vez e testá-lo em um grau razoável.
Obviamente, quando novos componentes forem concluídos, você deve testar como (e se) eles se integram antes de prosseguir.
Em resumo: pegue o princípio OO e ocultação de informações e suba outro nível!
PS: Faça muitos esboços ao projetar, é como uma arquitetura real!
PPS: Tente abordar o assunto de diferentes ângulos, pense fora da caixa (embora a caixa possa ser o caminho a seguir), discutir com colegas pode ser muito útil para isso ... e você tem algo sobre o que conversar durante o almoço.
fonte
A técnica que usei em projetos reais com razoável sucesso é o Responsible Driven Design, inspirado no livro de Wirfs-Brock.
Comece com as histórias de usuário de nível superior e, com os colegas, em um quadro branco, esboce as interações de alto nível que elas implicam. Isso dá a você a primeira idéia do que são os grandes módulos; e uma ou duas iterações de alto nível da placa CRC, como você deve ter estabilizado uma lista dos principais componentes, o que eles fazem e como eles interagem.
Em seguida, se alguma das responsabilidades for grande ou complexa, refine esses módulos até que você tenha coisas pequenas e simples o suficiente para serem objetos, executando as interações dentro do módulo para cada uma das principais operações identificadas pelas interações de nível superior .
Saber quando parar é uma questão de julgamento (que só vem com a experiência).
fonte
Padrões de design
Padrões de design criacional
Singleton - garanta que apenas uma instância de uma classe seja criada e forneça um ponto de acesso global ao objeto.
Factory (versão simplificada do Factory Method) - Cria objetos sem expor a lógica da instanciação ao cliente e refere-se ao objeto recém-criado por meio de uma interface comum.
Método de fábrica - Define uma interface para criar objetos, mas permite que as subclasses decidam qual classe instanciar e se refere ao objeto recém-criado por meio de uma interface comum.
Abstract Factory - Oferece a interface para criar uma família de objetos relacionados, sem especificar explicitamente suas classes.
Construtor - define uma instância para criar um objeto, mas permite que as subclasses decidam qual classe instanciar e permite um controle mais refinado do processo de construção.
Protótipo - especifique os tipos de objetos a serem criados usando uma instância prototípica e crie novos objetos, copiando esse protótipo.
Padrões de Design Comportamental
Cadeia de Responsabilidade - Evita anexar o remetente de uma solicitação ao seu destinatário, dando assim a outros objetos a possibilidade de lidar com a solicitação também. - Os objetos se tornam partes de uma cadeia e a solicitação é enviada de um objeto para outro através da cadeia até que um dos objetos o manipule.
Comando - Encapsula uma solicitação em um objeto, Permite a parametrização de clientes com solicitações diferentes e Permite salvar as solicitações em uma fila.
Intérprete - Com base em um idioma, defina uma representação para sua gramática, juntamente com um intérprete que use a representação para interpretar sentenças no idioma / Mapear um domínio para um idioma, o idioma para uma gramática e a gramática para um design hierárquico orientado a objetos
Iterador - Forneça uma maneira de acessar os elementos de um objeto agregado seqüencialmente, sem expor sua representação subjacente.
Mediador - Defina um objeto que encapsula como um conjunto de objetos interage. O mediador promove o acoplamento frouxo, impedindo que os objetos se refiram explicitamente, e permite variar a interação deles independentemente.
Observador - Defina uma dependência de um para muitos entre objetos para que, quando um objeto mudar de estado, todos os seus dependentes sejam notificados e atualizados automaticamente.
Estratégia - Defina uma família de algoritmos, encapsule cada um e torne-os intercambiáveis. A estratégia permite que o algoritmo varie independentemente dos clientes que o utilizam.
Método de Modelo - Defina o esqueleto de um algoritmo em uma operação, adiando algumas etapas para as subclasses / O Método de Modelo permite que as subclasses redefinam certas etapas de um algoritmo sem permitir que elas alterem a estrutura do algoritmo.
Visitor - Representa uma operação a ser executada nos elementos de uma estrutura de objeto. O Visitor permite definir uma nova operação sem alterar as classes dos elementos nos quais opera.
Objeto nulo - forneça um objeto como substituto pela falta de um objeto de um determinado tipo. / O Padrão de Objeto Nulo fornece um comportamento inteligente de não fazer nada, ocultando os detalhes de seus colaboradores.
Padrões de projeto estrutural
Adaptador - Converta a interface de uma classe em outra interface que os clientes esperam. / Adapter permite que as classes trabalhem juntas, que não poderiam de outra forma por causa de interfaces incompatíveis.
Ponte - Componha objetos em estruturas de árvore para representar hierarquias de partes inteiras. / Composite permite que os clientes tratem objetos individuais e composições de objetos de maneira uniforme.
Composto - Componha objetos em estruturas de árvore para representar hierarquias de parte inteira. / Composite permite que os clientes tratem objetos individuais e composições de objetos de maneira uniforme.
Decorador - adicione responsabilidades adicionais dinamicamente a um objeto.
Flyweight - use o compartilhamento para oferecer suporte a um grande número de objetos que têm parte de seu estado interno em comum, onde a outra parte do estado pode variar.
Memento - capture o estado interno de um objeto sem violar o encapsulamento e, assim, forneça um meio para restaurar o objeto no estado inicial quando necessário.
Proxy - forneça um "Espaço reservado" para um objeto para controlar referências a ele.
fonte
Eu recomendo que você use o BlueJ e também o ActiveWriter para aprender e também desenvolver um bom entendimento sobre os objetos. O livro recomendado também é um bom recurso.
Da Wikipedia :
Além disso, ele usa UML e, para mim, foi um bom recurso para compreender várias coisas sobre modelagem de objetos.
texto alternativo http://www.ryanknu.com/ryan/bluej.png
O ActiveWriter é uma ferramenta para modelar entidades e relações, também gera código e é fácil fazer alterações. Você economizará tempo e o desenvolvimento ágil é muito adequado.
(fonte: altinoren.com )
fonte
Primeiro de tudo - o design deve vir da sua alma. Você deve sentir isso por todas as suas fibras. Eu costumo andar por dois ou três meses antes de começar a fazer qualquer coisa, apenas andando pelas ruas (realmente). E pensando. Caminhar é uma boa meditação, você sabe. Então, permite que você se concentre bem.
Segundo - use OOP e classes apenas onde existe uma hierarquia de objetos naturais. Não 'estrague' isso artificialmente. Se não existir uma hierarquia estrita (como na maioria dos aplicativos de negócios) - vá para processual / funcional ou, pelo menos, use objetos apenas como contêineres de dados com acessadores isolados.
E a última - tente ler o seguinte: O Algoritmo do Pensamento Criativo
fonte
Apenas citando http://www.fysh.org/~katie/computing/methodologies.txt
E no centro do RUP há uma pequena área em que você precisa usar os talentos do projeto OO ... se você não os possui, é como ter uma metodologia para executar os 100m.
"Etapa 1: escreva sobre como correr muito rápido. Etapa 2: vá e faça um plano da pista. Etapa 3: vá e compre shorts de lycra bem apertados. Etapa 4: corra muito, muito, muito rápido. Etapa 5: cruze primeiro a linha "
Esse passo 4 é o mais difícil. Mas se você colocar muita ênfase em 1,2,3 e 5, é possível que ninguém perceba e, provavelmente, você poderia ganhar muito dinheiro vendendo a metodologia para atletas que pensam que há algum "segredo" nos 100m corredor
fonte
Você fez uma pergunta que muitos autores usam para escrever um livro. Há várias metodologias e você deve escolher uma que pareça "mais bonita" para você.
Eu posso recomendar o livro "Domain Driven Design", de Eric Evans. Além disso, consulte o site dddcommunity.org .
fonte
Eu acho que a resposta aqui deve ser muito diferente, dependendo da experiência do mundo real do cara perguntando.
Se você tem apenas um ou dois anos de experiência profissional, deve ir ao ponto que é: como chegar ao ponto de realmente conhecer seus dados e entender exatamente o que está tentando fazer?
Sim, se você trabalha no mundo real há mais de 5 anos, pode escolher entre qualquer um dos muitos modelos ou técnicas de processos de desenvolvimento de software.
Mas você não obtém experiência lendo apenas livros. Você deve aprender trabalhando em um bom grupo, sob uma boa liderança.
Se isso não for possível, você deve fazer sozinho. Comece iterando codificando um pedaço de código provavelmente muito desagradável, aprendendo seus erros, descartando tudo, codificando um melhor e assim por diante.
Você aprenderá muito sobre sua base de código. As ferramentas são ferramentas, elas não ensinarão nada a você.
fonte
Se você possui experiência no domínio do projeto, irá trabalhar como, por exemplo, bancário. É fácil estruturar seus objetos e você sabe como essas melhorias acontecem todos os dias.
Se você não tiver esse conhecimento, trabalhe com alguém que tenha esse conhecimento e converta essas idéias em detalhes técnicos.
Se você está confuso sobre como estruturar o design do seu projeto. Siga cegamente o livro "programador pragmático". Eu estava na mesma situação antes, tente ler um capítulo desse livro. você verá a diferença. Isso mudará a maneira como você pensa como desenvolvedor de software.
fonte
Você conhece a etapa 3. Você precisa dominá-la. Quero dizer, através de muita prática para torná-lo sua segunda natureza. Isso ocorre porque o método que você aprende é simplesmente contrário ao que costumávamos ter. Então você precisa realmente dominá-lo. Caso contrário, você sempre voltará à sua maneira original de fazer as coisas. De alguma forma, isso é parecido com o Test Driven Process, em que muitos desenvolvedores java o abandonam após algumas tentativas. A menos que eles dominem completamente, caso contrário, é apenas um fardo para eles
Escreva casos de uso, especialmente para cursos alternativos. Cursos alternativos ocupam mais de 50% do nosso tempo de desenvolvimento. Normalmente, quando seu PM atribui uma tarefa a você, por exemplo, crie um sistema de login, ele pensará que é simples, você pode levar 1 dia para finalizar. Mas ele nunca leva em consideração o que você precisa considerar: 1. e se o usuário digitar a senha errada, 2. o que se o usuário digitar a senha errada por 3 vezes, 3. o que se o usuário não digitar o nome do usuário e etc. Você precisa listá-los e mostrá-lo ao seu PM, peça a ele para reagendar o prazo.
fonte
Receio que esta não seja uma resposta que as pessoas gostem de ouvir . De qualquer forma, deixe-me expressar minha opinião.
OOP deve ser visto como um dos paradigmas, não como o paradigma superior. OOP é bom para resolver certos tipos de problemas, como o desenvolvimento de uma biblioteca de GUI. Também se encaixa no estilo de desenvolvimento de software geralmente seguido por grandes empresas de software - uma equipe de elite de designers ou arquitetos estabelece o design de software em diagramas UML ou em algum outro meio semelhante e uma equipe menos esclarecida. desenvolvedorestraduza esse design para o código fonte. OOP oferece pouco benefício se você estiver trabalhando sozinho ou com uma pequena equipe de programadores altamente talentosos. Então, é melhor usar uma linguagem que suporte múltiplos paradigmas e o ajude a criar um protótipo rapidamente. Python, Ruby, Lisp / Scheme etc são boas escolhas. O protótipo é o seu design. Então você melhora nisso. Use o paradigma melhor para resolver o problema em questão. Se necessário, otimize os pontos de acesso com extensões escritas em C ou em algum outro idioma do sistema. Ao usar um desses idiomas, você também obtém extensibilidadede graça, não apenas no nível do programador, mas também no nível do usuário. Idiomas como o Lisp podem gerar e executar código dinamicamente, o que significa que seus usuários podem estender o aplicativo escrevendo pequenos trechos de código, no idioma em que o próprio software está codificado! Ou, se você optar por escrever o programa em C ou C ++, considere incorporar um intérprete para um idioma pequeno como Lua. Exponha as funcionalidades como plug-ins escritos nesse idioma.
Penso que, na maioria das vezes, OOP e OOD criam software que é vítima de excesso de design.
Para resumir, minha maneira preferida de escrever software é:
O último recurso permite que o software se adapte facilmente a requisitos específicos de usuários (inclusive eu!).
fonte
Eu uso o Design Orientado a Testes (TDD). Escrever o teste primeiro, na verdade, ajuda a levar você a um design limpo e correto. Veja http://en.wikipedia.org/wiki/Test-driven_development .
fonte
Aprenda padrões de design . Foi minha revolução pessoal nos últimos dois anos em relação ao POO. Pegue um livro. Eu recomendaria este:
Head First Design Patterns
Está em Java, mas pode ser extensível a qualquer idioma.
fonte
Honestamente, um bom passo seria voltar atrás e analisar o fluxograma e o diagrama de sequência. Existem vários sites bons que mostram como fazê-lo. Acho que é inestimável quando se analisa como quero dividir um programa em classes, pois sei exatamente o que o programa precisa ser inserido, calculado e gerado e cada etapa pode ser dividida em uma parte do programa.
fonte
Conforme respondido em Qual é o fluxo de trabalho que você segue para criar o software que está prestes a escrever?
fonte
Uma técnica útil é relacionar sua descrição exclusiva do problema a algo que você pode encontrar no mundo real. Por exemplo, você está modelando um sistema de saúde complexo que conquistará o mundo. Existem exemplos que você pode chamar prontamente para modelar isso?
De fato. Observe como a farmácia lateral funcionaria ou a sala do médico.
Reduza o problema do seu domínio para algo compreensível para você; algo com o qual você pode se relacionar.
Depois que os "players" no domínio começarem a parecer óbvios e você começar a modelar seu código, opte por uma abordagem de modelagem "provedor-consumidor", ou seja, seu código é o "provedor" do modelo e você é o "consumidor" "
Relacionar-se com o domínio e entendê-lo em alto nível é parte essencial de qualquer design.
fonte
Durante minhas aventuras de projetar estruturas de classe, notei que é muito útil começar escrevendo algum pseudo-código. Isso significa: começo com "escrevendo" alguns fragmentos gerais do código do aplicativo em um nível mais alto, brinco com ele e descubro os elementos que estão aparecendo - de fato, os elementos que eu - como programador - gostaria de usar. É um ponto de partida muito bom para projetar a estrutura geral dos módulos e suas interações. Após algumas iterações, toda a estrutura começa a se parecer mais com um sistema completo de classes. É uma maneira muito flexível de projetar partes do código. Você pode chamá-lo de design orientado a programador.
fonte