Como faço para superar a paralisia pela análise ao codificar?

37

Quando inicio um novo projeto, muitas vezes começo a pensar nos detalhes da implementação. "Onde eu vou colocar o DataBaseHandler? Como devo usá-lo? As classes que querem usá-lo estender de alguma superclasse abstrata ...? Devo usar uma interface? Que nível de abstração eu vou usar na minha classe que contém métodos para enviar solicitações e analisar dados? "

Acabei parando por muito tempo porque quero codificar para extensibilidade e reusabilidade. Mas eu acho quase impossível passar pensando em como implementar perfeitamente.

E então, se eu tentar apenas dizer "estrague tudo, apenas faça isso!", eu bati em uma parede de tijolos rapidamente porque meu código não está organizado, eu misturei níveis de abstração, etc.

Quais são algumas técnicas / métodos que você tem para lançar em um novo projeto ao mesmo tempo em que configura uma estrutura lógica / modular que será bem dimensionada?

- - EDITAR - -

Bem, este é o tipo de pergunta que é difícil aceitar uma resposta, mas queria obter mais feedback, ver se há algum consenso. O TDD soa muito legal e, francamente, eu estava querendo saber mais sobre o uso do JUnit, etc. Ao mesmo tempo, o que os fãs do TDD pensam sobre o fato de que um ponto legítimo com relação ao TDD resolver meu problema? questões particulares, é que o TDD não parece realmente abordar a questão do design. Claro, eu concordo que o TDD me ajudará a definir o que eu quero fazer e então eu posso trabalhar gradualmente com o como, mas existem muitos padrões / estruturas de projeto gerais diferentes que poderiam passar pelo teste de unidade. É isso mesmo: testa unidades individuais. Eu acho que estou um pouco confuso ... Eu não sei. Talvez eu esteja apenas tentando procrastinar ainda mais tentando descobrir alguma fórmula mágica, mas eu gostaria de ouvir como alguns dos veteranos abordam esta área ...

Obrigado!

    
por LuxuryMode 23.06.2011 / 05:22
fonte

9 respostas

16

Eu recomendo usar o Desenvolvimento orientado a testes , é preciso algum tempo para se acostumar especialmente quando se trabalha com um bom IDE, como eclipse, mas as vantagens são ótimas.

Basicamente, o que você faz é escrever os testes no seu código antes de escrever o próprio código. Então, você é forçado a olhar seu código do ponto de vista de como ele será usado, o que significa que suas interfaces evoluem em mais cenários que você implementa.

Outra característica é que você implementa em pedaços muito pequenos (eles crescem quanto mais experiente você estiver na técnica e na programação), o que obriga a se concentrar em um problema muito pequeno e bem definido a cada vez.

E também desde que você primeiro escreve um teste e só então implementa, você tem um teste com falha na sua frente. Então, se você é como a maioria dos programadores, você não vai se deixar levar por uma análise louca, porque você pensa: "Eu preciso fazer esse teste funcionar".

Um pequeno exemplo de java:
Digamos que eu queira desenvolver um programa que leia e escreva uma mensagem de um banco de dados.

Então eu começo com a primeira ação bem definida, eu preciso de um DB:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
}

ok, então aqui vejo que preciso implementar a classe DbConnector.getDB para que ela retorne o banco de dados, até que esse teste falhe. Eu vou e faço isso ...

Não adiciono a próxima coisa que quero fazer, carregar a mensagem do banco de dados:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
}

Agora eu adicionei outro pequeno recurso ao banco de dados que é buscar uma mensagem, vou implementá-la e, uma vez terminado, continuo com um recurso de cada vez até chegar a algo como isto:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
  message = "foo bar";
  db.storeMessage(message);
  message = db.fetchMessage();
  assertEquals("foo bar", message);
}

Pode parecer um exemplo muito simples, mas isso também funciona para tarefas mais complexas. Eu sei que é muito demorado no começo, mas como você se acostuma com isso, você vê que, na verdade, é muito mais eficiente. Por um lado você evita a paralisia por análise e por outro você obtém um código muito mais robusto que geralmente tem menos bugs e passa por menos iterações.

    
por 23.06.2011 / 05:56
fonte
10

Isso acontece comigo, então eu tenho o hábito de aceitar (e abraçar) uma mentalidade de refatoração contínua. Eu faço a coisa mais simples que poderia funcionar, depois eu limpo, organizo, decoco, testo e continuo.

Isso não quer dizer que não há muito planejamento acontecendo, mas acontece muito rapidamente e mais frequentemente como rabiscos em sucata ou na minha cabeça. Ao todo, às vezes eu chamo esse pequeno processo de micro-iterações porque elas levam de 5 a 20 minutos cada, e da experiência leva de 2 a 3 para terminar o que estou trabalhando (dependendo do que estou fazendo, obviamente).

Como uma nota lateral: Eu tenho ensinado um número de pessoas em diferentes formas de escrita (relatórios, ensaios e redação técnica em geral) e esta é a mesma maneira que eu os faço escrever coisas para superar o bloqueio de escritor. "Apenas deixe escapar qualquer coisa sobre o seu tópico que venha à mente na página. Então nós faremos sentido e separaremos tudo em parágrafos e verificaremos o fluxo. Se for necessário, nós até mesmo o reescreveremos."

    
por 23.06.2011 / 05:55
fonte
2

Algumas coisas que podem funcionar:

  • Identifique o problema central que você está tentando resolver - qual é o coração da coisa que você quer fazer? Implemente apenas isso e o mínimo de código de suporte para executá-lo. Uma vez que funcione para sua satisfação, construa iterativamente, refatorando sem piedade a cada passo.
  • Veja se outros paradigmas de programação funcionam para você. Apesar de todos os seus méritos, a programação orientada a objetos não é a resposta para todos os problemas, e nem todos os cérebros dos programadores trabalham dessa maneira. Pegue uma linguagem funcional (pura); escreva algum código processual; mergulhe no nível de hardware e faça algum C ou talvez até mesmo assembler; Algumas linguagens que podem sacudir sua mente (supondo que você esteja usando algo como C ++ / Java / C # / VB / ...): Haskell, ML, Lisp (vários dialetos para escolher), Erlang, Prolog, Smalltalk, Javascript (se você deixar de tentar fazê-lo se comportar como Java e abraçar sua natureza de fechamento), C, Pascal, awk e provavelmente mais uma dúzia. A principal característica é que eles precisam ser muito diferentes do que você usa agora. Isso não é algo que você queira fazer em um grande projeto com muito em jogo, mas fazer isso para projetos paralelos (pessoais ou relacionados ao trabalho) lhe dará novos insights.
  • Use um método de design radicalmente diferente. Veja se você pode pegar o desenho de um ângulo diferente. Eu suponho que você geralmente começa a projetar colocando suas aulas; Que tal você começar com estruturas de dados para uma mudança? Ou que tal você projetar a interface do usuário primeiro, literalmente desenhando formulários de entrada antes de projetar qualquer funcionalidade?
por 23.06.2011 / 07:57
fonte
1

Para muitas decisões de design, pode ajudar a fazer um "pico", que é um esforço de pesquisa curto e limitado no tempo, no qual você pode explorar algumas opções de arquitetura ou design codificando para um protótipo descartável. Por exemplo, você poderia explorar o uso de alguma biblioteca de código aberto ou como você organizará suas classes e interfaces. A chave é mantê-lo curto, para que você possa tentar outra abordagem, se a primeira for insatisfatória e, com sorte, você obterá conhecimento suficiente no exercício para melhor tomar as decisões de arquitetura ou para provar o conceito. O exercício em si envolve codificação imediata que ajuda a sair do "bloco de escritores" sem necessariamente se comprometer com o "git 'er done" cedo demais.

Depois disso, é benéfico usar a abordagem TDD ou BDD que Asaf mencionou para avançar com a implementação do projeto.

    
por 23.06.2011 / 06:36
fonte
1

Você não vai precisar , então não pense muito no começo.

Invista mais tempo para definir, entender o objetivo e o problema.

"Extensibilidade e reutilização" é o resultado natural do ciclo de vida de programas de software bem escritos.

    
por 23.06.2011 / 10:21
fonte
0

Suponho que estamos analisando um projeto de tamanho médio.
Eu começaria indo na prancheta. Você deve ter seus requisitos funcionais e não funcionais prontos antes de fazer isso. Primeiro, você cria a arquitetura do software, ou seja, analisa todos os padrões arquiteturais que se adequam às suas necessidades. Depois de decidir como sua arquitetura se parece, você deve entrar no design de baixo nível e observar todas as entidades. classes e funcionalidade. Aqui, você tentará identificar os padrões de projeto que se ajustam. No processo, você saberá quais são suas classes base e as interfaces necessárias. Em seguida, você pode criar a estrutura e executar alguns testes rápidos para Veja se isso satisfaz todos os seus requisitos não funcionais, então eu iria com Test Driven Development como @Asaf sugeriu.

Lembre-se, Apesar de gastar um bom tempo em design e arquitetura, sempre esteja disposto a revisitar a arquitetura, se necessário.

    
por 23.06.2011 / 07:38
fonte
0

Acho que esta é uma ótima pergunta e nada funcionará para todos. Eu acho que tal paralisia é um subproduto natural de se tornar mais e mais competente em seu campo. Dito isso, aqui estão algumas coisas que faço que ajudam, mas não resolvem o problema:

  • Ponha seu projeto intocado de lado e trabalhe na versão fugly. Esta é a versão em que você diz a si mesmo: uma. O código não deve ser bonito. Na verdade, diga a si mesmo: refatoração e reformatação importantes não são permitidas. Que seja absolutamente desorganizado e livre das amarras da boa codificação. b. Só tem que funcionar. c. É sempre surpreendente para mim o que eu aprendo sobre o espaço do problema quando descarto todas as outras preocupações. Eu também acabo com pequenos boatos que muitas vezes me ajudam a chegar ao design certo de uma forma mais esclarecida.

  • Separe um bloco de tempo decente no qual você está no projeto, sem precisar de um computador. Tente conceitualizar o que você realmente está tentando realizar e procure aquele zen mágico que transcende a loucura do Padrão de Design / OO.

por 23.06.2011 / 07:39
fonte
0

Dê uma expressão concreta aos seus pensamentos: escreva / digite-os, desenhe-os ou o que for. Isso ajudará você a revisitar seus pensamentos quando necessário; isso vai impedi-lo de entrar em círculos; ajuda você a pensar com mais clareza.

Sempre que me vejo indo a lugar nenhum e a todo lugar pensando em algo, eu os digito e isso me ajuda a pensar com clareza.

    
por 23.06.2011 / 09:19
fonte
0

Eu costumo começar do zero, criar o protótipo mais simples possível e fazer algo funcionar. Use o protótipo para fazer engenharia reversa dos casos de teste do caminho feliz, os casos de teste para orientar as interfaces e, em seguida, pense nos contratos pré / pós para ajudar a construir a cobertura de teste.

Não se preocupe com abstração, otimização ou verificação até que o problema seja totalmente compreendido.

    
por 25.10.2011 / 11:35
fonte