O que é um código bonito em C ++ e por que a maioria dos programadores se importa tanto? [fechadas]

8

Como a maioria dos projetos usa uma API C ++, eles lidam com restrições da API e restrições do próprio projeto.

Sou iniciante em programação, não gosto de usar OOP porque ninguém claramente me explicou POR QUE é tão importante restringir-se ao escopo privado para impedir que outros programadores quebrem algum tipo de consistência na organização de dados.

Ainda posso concordar com o OOP, pois ele ainda permite criar ótimas coisas como Qt e Ogre3D, mas essas são apenas APIs, não aplicativos, e esses códigos precisam ser perfeitos para que ninguém possa criticar o trabalho.

Não entendo por que a maioria dos programadores, uma vez que eles criam aplicativos e não APIs, querem criar um código perfeito, como eles projetam algum código genial e perdem tempo com isso.

jokoon
fonte
19
Dê alguns anos para voltar ao seu código antigo e não perfeito e tentar adicionar recursos a ele, corrigir erros nele, etc. Você verá por que as pessoas se preocupam em fazê-lo da maneira mais correta e clara possível. tempo ao redor.
R0MANARMY
Consulte (esta pergunta) [ programmers.stackexchange.com/q/65216/8823] . Não é porque você não é um programador, mas porque há alguma boa descrição do porquê de código bonito é bom
Austin Hyde
2
Esta é uma pergunta sobre código bonito, OOP ou escopo privado? Eu realmente não posso dizer.
Sean McMillan
1
Uau ... não sei por onde começar. Espero nunca ter que ver ou trabalhar com o seu código ...
Rig
1
Bom código e boa API têm muitas coisas em comum. Um bom código OOP deve ter uma interface que se pareça exatamente com uma API bem projetada.
Rwong 11/03/12

Respostas:

12

Você já ouviu o ditado "Ninguém é uma ilha" ?

Para a maioria dos programadores, isso é verdade. Quase ninguém escreve código que é "apenas um aplicativo". Em muitos aplicativos não triviais, um programador grava a interface do usuário que precisa ser facilmente modificada por um designer. Ele também deve permitir uma ligação clara de dados à lógica de negócios (Controller, ViewModel ou o que você quiser chamar). Outro programador escreve esse controlador, que geralmente pode ser extremamente complexo, mas precisa ser simples o suficiente para ser facilmente consumido pelo programador front-end. Esse codificador de lógica de negócios está consumindo código de quem escreveu a camada de dados (Modelo, Repositório etc.). Você não precisa usar o OOP, no entanto, o que é muito bom é permitir que você encapsule a lógica por trás de uma interface para que outras pessoas com quem você trabalha possam usar seu código sem quebrá-lo (supondo que você tenha testado essa interface!). Abstração não é a bala de prata,

Então você pode estar dizendo agora "Sério, sou uma exceção e ninguém verá meu código ou trabalhará com ele". É justo, mas quando você precisar corrigir um bug nesse aplicativo daqui a alguns meses ou quiser adicionar alguns recursos, provavelmente verá que a pessoa que escreveu esse código na época e a pessoa que o está modificando agora estão duas pessoas totalmente diferentes. Costumamos presumir que lembraremos das coisas, o que é o principal motivo pelo qual escrevemos códigos desleixados, mas a verdade é que daqui a seis meses você não se lembrará dos hacks que você colocou no seu aplicativo agora. Seu futuro eu terá o suficiente para lidar, então por que não dar uma folga a ele?

Morgan Herlocker
fonte
43

Qualquer tolo pode escrever código que um computador possa entender. Bons programadores escrevem código que os humanos podem entender. ~ Martin Fowler

Em poucas palavras, é por isso que você quer se preocupar com um código bonito.

Você não escreve código para o computador. O computador entende apenas o código binário de qualquer maneira (que é produzido a partir do seu código-fonte por meio de compiladores e intérpretes). Ele não se importa com a beleza ou a clareza ou mesmo se o seu código faz o que é suposto fazer.

Você escreve código para seus colegas programadores. E eles fazem o mesmo por você. Se você não consegue entender um pedaço de código escrito por outra pessoa, então quais são suas chances de encontrar e corrigir um bug ou adicionar novas funcionalidades?

wolfgangsz
fonte
1
Eu acrescentaria que é especialmente fácil escrever código totalmente enigmático em C ++, e é por isso que isso é ainda mais importante nessa linguagem!
deadalnix
1
Bem, eu realmente não concordo com esta citação, código reutilizável é um bom código, é verdade, mas as linguagens são criadas para que os programadores possam trabalhar mais rapidamente, não necessariamente para serem lidos por outros programadores. É doloroso ler o código; portanto, coloque comentários ou altere o design para torná-lo mais compreensível para um ser humano, sim, mas um bom design nem sempre vem com "fácil de entender". Um programa pode executar tarefas simples e complicadas, e as linguagens de programação podem limitar a capacidade de projetar aplicativos sofisticados. A linguagem de programação facilita as coisas, não é mais sofisticada.
jokoon
3

O que outros disseram como você nunca sabe se pode precisar do seu código novamente no futuro, é claro.

Mas para mim há um ponto importante, porque eu sempre tento escrever um código bonito:

É um treinamento para melhorar.

Se aprendo algo novo sobre uma linguagem que uso ou sobre alguns conceitos gerais de programação, tento imediatamente usá-la, tentando fazer parte do meu fluxo de trabalho diário e da cadeia de ferramentas mental.

Se você ler apenas sobre algo como POO, esquecerá a maior parte dentro de algumas semanas. E você nunca receberá o treinamento sobre como aplicá-lo adequadamente a grandes problemas, desde que não se ensine aplicando-o a pequenos problemas.

Exemplo:

Por que é importante restringir-se ao escopo privado?

Em pequenos projetos, não é. Alguns idiomas (por exemplo, Ruby) até desencorajam esse tipo de encapsulamento até certo ponto. Mas existem usos para isso. Muitos.

E usá-lo vem com certos problemas e muitos detalhes que você precisa aprender. Usá-lo em pequenos projetos ensinará isso a você. Você verá algumas mensagens de erro do seu compilador que são novas para você e, em um projeto pequeno, poderá encontrar a fonte do problema mais fácil.

Você aprende sobre espaços para nome em C ++. Não há muita necessidade deles em pequenos projetos. O mesmo vale para a estrutura genaral dos arquivos de cabeçalho e inclui. Você pode aprender tudo isso desde o início na proteção de uma pequena base de código.

thorsten müller
fonte
1

É tudo sobre ter que manter o código legado. E em alguns meses o código que você está escrevendo agora se tornará um código legado que você também precisará manter.

Codificação para psicopatas violentos

Chave na mão
fonte
1
  1. O que R0MANARMY disse em seu comentário. O código "limpo" e "bonito" facilita a leitura, a compreensão, a manutenção, a alteração e a correção no futuro, não apenas para você, mas também para os outros que o perseguem.

  2. Algumas pessoas, quando fazem algo, tentam fazer o melhor que podem, da melhor maneira possível, para que seja "perfeito" ou, nesse caso, "bonito". Descobri que há uma grande sobreposição entre esse conjunto de pessoas e desenvolvedores (inclusive eu!).

Porém, lembre-se de que "bonito", "limpo" ou "elegante" são termos altamente subjetivos que significam coisas diferentes para pessoas diferentes. Pelo que vi, código amplamente considerado bonito, limpo e / ou elegante,

  • É fácil de ler e entender
  • Não tem, ou pouco, código desnecessário
  • É facilmente extensível e / ou modular
  • Está bem documentado
  • Segue todos os padrões para idiomas / tecnologias relacionados
  • E não faz nada inesperado (por exemplo, efeitos colaterais em um método acessador)
Austin Hyde
fonte
1

Eu concordo com a coisa de manutenção. Apenas tente fazer um projeto relativamente grande e você verá toda a bagunça que envolve suas mãos na correção de bugs, na adição de novos recursos, etc. Mas para falar sobre beleza:

Código bonito é a qualidade desejada do produto porque a programação (pelo menos C ++) é uma ART.

videiras
fonte
1
Embora com a introdução de lambdas que agora envolvem menos tubarões em formaldahyde
Martin Beckett
1

[...] ninguém conseguiu me explicar claramente POR QUE é tão importante restringir-se ao escopo privado para impedir que outros programadores quebrem algum tipo de consistência na organização de dados.

Em uma equipe pequena o suficiente com uma base de código pequena o suficiente para ser realmente bem coordenada com bons padrões (pode ser apenas uma pessoa), geralmente você pode encontrar um software confiável que deixa todos os dados em aberto para que qualquer pessoa possa tocar em todos os campos de dados de uma structexposição aberta e com a structdefinição aberta para qualquer pessoa que inclua esse cabeçalho para acessar. A lei de Murphy nem sempre se aplica nesses casos.

Mas eu trabalhei no cenário oposto de uma enorme base de código com muitos milhões de LOC, datados dos anos 80, com uma grande equipe de desenvolvedores de todo o mundo, onde só nos encontramos cara a cara a cada poucos meses, de maneira pouco coordenada, às vezes mal falando o mesmo idioma, sem padrões de codificação, exceto o SDK que as pessoas geralmente não seguiam de qualquer maneira, sem testes de unidade / integração, usando o SVN sem ramificação e às vezes passando seis semanas sem verificar o código, apenas para nos bombardear com bugs, e Não foi até então que eu realmente entendi o valor da informação ocultando e mantendo os invariantes .

Lidei com os bugs em que nem conseguia reproduzir o problema de maneira consistente na minha máquina e, às vezes, nenhum de nós conseguia entre toda a equipe. E quando finalmente consegui reproduzir com sorte o problema relatado pelo usuário ou algo semelhante a ele após todos os tipos de tentativas e erros (e as tentativas e erros geralmente levavam horas porque a ineficiência do nosso software combinava com a execução em depuração da produção final do usuário os dados geralmente demoravam mais de 15 minutos apenas para carregar os dados); eu o rastreava para algo como a structpara um tipo de string que tinha um lennúmero negativo para o lixo, como um comprimento de string -921141282.

Isso nunca deveria acontecer, mas quem fez isso? Então eu tive que definir pontos de interrupção de memória e descobrir e, quando finalmente o fiz, era como uma interação em cascata de variáveis ​​não inicializadas sendo usadas aritmeticamente, o que acabou resultando em um lencampo de string sendo definido como um número de lixo negativo, e esse código não foi modificado em anos. Voou sob o radar.

E durante todo esse tempo, depois de encontrar muitos bugs como esse, pensei comigo: quanto mais confiável seria o nosso software se apenas o usasse getterse setters? Getters e setters são geralmente indicativos dos piores tipos de designs de interface possíveis, mas um setter pode pelo menos desencadear uma falha de afirmação se alguém tentar definir o comprimento de uma string com um valor negativo. Poderíamos ter pegado esses anos de insetosantes, no momento exato em que foi introduzido em segundos, não no culminar de horas de esforço investigativo. E isso é apenas pensar egoisticamente como desenvolvedor; ele não cobre todas as horas de luto que poderia ter salvado os usuários e a equipe de controle de qualidade também. Você sabe que seu sistema está em um péssimo lugar quando está sonhando com o quão melhor poderia ser se usasse setters e getters em face dos últimos 35 bugs que você passou a noite inteira consertando.

Tivemos até casos em que structsforam documentados de maneira que ninguém mais deveria acessar esses campos de dados, apenas para encontrar locais no sistema que acessam esses campos de dados.

Portanto, esses são os tipos de coisas que você pode realmente apreciar ao máximo ao enfrentar o pior cenário, mas muitas vezes o fará a menos que tenha a sorte de passar o resto da vida trabalhando em bases de código menores com equipes bem coordenadas e padrões de codificação fortes.

O que é um código bonito em C ++ [...]?

Essa é difícil. Eu ainda estou tentando descobrir isso. A maior parte do código que considero bonito que escrevi ao longo dos anos, ou pelo menos confiável, relativamente atemporal e estável (sem precisar / querer mudanças) foi escrita em C e, recentemente, em Lua. Ainda luto para escrever código C ++ que parece passar no teste do tempo a ponto de não refletir sobre isso alguns anos depois e pelo menos desejar poder alterá-lo. Eu sinto que ficou mais fácil desde C ++ 11, mas preciso de alguns anos para descobrir como meu código consegue sobreviver sem precisar de alterações para ter certeza. Para mim, a "beleza" definitiva é a "estabilidade", como no código que não precisa e nem tenta outras alterações, mas ainda permanece relevante e útil nos próximos anos, já que "


fonte
0

Bem, definir interfaces limpas e úteis ("bonito" é um qualificador ruim) tem tudo a ver com garantir que:

  1. O usuário entende com o mínimo de esforço como usar seu objeto (ou sistema de objetos) apenas lendo sua interface.
  2. O usuário terá dificuldade em usar o objeto / sistema de maneira errada - a interface dificulta a execução de algo errado ou o sinal de problemas com antecedência.
  3. A interface descreve uma abstração útil.

Os pontos 1. e 2. exigem que você pense muito sobre o contrato que está firmando com seu usuário. Esse contrato, ou protocolo, é a maneira de comunicar ao usuário como ele pode usar seu sistema. Por exemplo, funções-membro somente leitura (funções-membro const) dizem muito sobre quais situações você deve poder chamar essa função. Da mesma forma, os atributos de cada função dividem o usuário para reunir e fornecer as informações mínimas necessárias para o funcionamento do sistema.

Todos os pontos juntos sugerem que suas interfaces devem mostrar apenas serviços úteis para o usuário. Primeiro, para limitar o uso do sistema pelo usuário apenas para o que o sistema foi criado. Segundo, evitando que ele manipulasse o estado interno de maneira errada. Portanto, a maneira mais fácil no C ++ de conseguir isso é colocar todos os membros privados e declarar explicitamente quais serviços seu sistema fornece, usando funções de membro ou globais (no (s) namespace (s)). Outra maneira é usar o idioma PImpl.

Terceiro, e o mais importante: sua interface deve fornecer uma abstração útil, o que significa que o usuário não precisa entender a implementação. Quando dirijo um carro ou uma máquina de lavar, não quero saber como ele é construído lá dentro (mesmo que eu seja um geek em tecnologia ...). Eu só preciso usá-lo e não ter que me preocupar com o que está dentro.

É difícil.

Qualquer definição de protocolo, como projetar uma linguagem de programação ou projetar uma classe, não é tão óbvia quanto se pensa primeiro. É necessária muita experiência para apreciar as subteleiras das interfaces de design.

Tudo isso não é revelador quando você define estruturas ou classes que representam conceitos de nível muito baixo. Quanto mais alto você obtém do hardware, mais precisa ter interfaces limpas, claras e úteis.

Klaim
fonte