Gostaria de acrescentar uma resposta a essa pergunta, já que tenho andado a percorrer algum Java bom, ruim, mas principalmente feio ultimamente e tenho uma carga enorme de super generalizações brutas sobre desenvolvedores Java e Java vs. JS e JS e Devs JS que podem realmente se basear em algo que lembra vagamente a verdade útil.
Existem IDEs, mas pode ser útil entender por que não existem muitos
Eu tenho experimentado o Webstorm agora que me sinto atraído pelo desenvolvimento do Node e não é ruim o suficiente que eu comprei, mas continuo a abrir arquivos js no Scite com mais frequência do que o WS. A razão para isso é que você pode fazer muito mais com muito menos em JS, mas também porque o trabalho da interface do usuário fornece feedback imediato, as ferramentas de desenvolvimento do navegador (especialmente o Chrome e o Firebug) são realmente excelentes e (considerando contextos que não são do navegador) ) re-executar o código alterado é rápido e fácil sem uma etapa de compilação.
Outra coisa de que estou bastante convencido é que os IDEs basicamente criam sua própria demanda, permitindo códigos desleixados que você realmente não pode pagar em JavaScript. Deseja saber como gerenciamos em JS? Pode ajudar começar tentando escrever algo não trivial em Java sem um IDE e prestar muita atenção às coisas que você deve começar a fazer e pensar para realmente conseguir manter / modificar esse código sem que um IDE se mova frente. Na IMO, essas mesmas coisas ainda são críticas para a criação de código sustentável, se você tem um IDE ou não. Se eu tivesse que escrever um currículo de programação de quatro anos, não permitiria que você tocasse em um IDE nos dois primeiros anos, com o objetivo de não distorcer as ferramentas e dependências.
Estrutura
Devs JS experientes que lidam com aplicativos complexos podem e estruturam seu código. De fato, é uma coisa em que tendemos a melhorar com uma história antiga que não possuía IDEs para ler o código para nós, mas também porque linguagens poderosamente expressivas podem expressar poderosamente bases de códigos de desastre completamente não-sustentáveis muito rapidamente, se você não codificar cuidadosamente.
Na verdade, eu tive uma curva de aprendizado bastante íngreme ao entender nossa base de código Java recentemente, até que finalmente percebi que nada disso era OOP adequado. As classes nada mais eram do que conjuntos de métodos vagamente relacionados, alterando dados disponíveis globalmente em beans ou DTOs ou getters / setters estáticos. Essa é basicamente a mesma velha fera que o OOP deveria substituir. Então parei de olhar e pensar no código basicamente. Acabei de aprender as teclas de atalho e rastrear as bagunças e tudo correu muito mais suavemente. Portanto, se você ainda não tem o hábito, pense muito mais no OOD.
Um aplicativo JS bem estruturado no nível mais alto tenderá a consistir em funções complexas (por exemplo, jQuery) e objetos interagindo entre si. Eu argumentaria que a marca de um aplicativo bem estruturado e de fácil manutenção em qualquer idioma é que é perfeitamente legível se você está olhando para ele com um IDE ou o Notepad ++. Essa é uma das principais razões pelas quais eu sou altamente crítico quanto à injeção de dependência e ao TDD do primeiro teste levado ao extremo.
E, finalmente, deixe de ir às aulas. Aprenda a herança prototípica. Na verdade, é bastante elegante e fácil de implementar quando você realmente precisa de herança. No entanto, acho que as abordagens de composição tendem a funcionar muito melhor no JS, e eu pessoalmente começo a ficar doente e a ter EXTJS night-terrors sempre que vejo mais de um ou dois níveis de herança acontecendo em qualquer idioma.
Princípios básicos primeiro
Estou falando das coisas principais das quais todas as outras boas práticas devem derivar: DRY, YAGNI, o princípio do mínimo espanto, separação limpa de domínios problemáticos, gravação em uma interface e gravação de código legível humano são o meu núcleo pessoal. Qualquer coisa um pouco mais complexa que defenda o abandono dessas práticas deve ser considerada Kool Aid em qualquer idioma, mas especialmente em um idioma como o JavaScript, onde é extremamente fácil deixar um legado de código muito confuso para o próximo cara. Acoplamentos frouxos, por exemplo, são ótimos, até você ir tão longe que nem consegue dizer onde está acontecendo a interação entre os objetos.
Não tema a digitação dinâmica
Não há muitos tipos principais de JavaScript. Na maioria das vezes, as regras de conversão dinâmica são práticas e diretas, mas vale a pena aprendê-las para que você possa aprender melhor a gerenciar o fluxo de dados sem projeções desnecessárias e rotinas de validação inúteis. Confie em mim. Tipos rigorosos são ótimos para desempenho e detecção de problemas na compilação, mas não protegem você de nada.
Aprenda a porcaria das funções e fechamentos JS
As funções de primeira classe de JS são, sem dúvida, o principal motivo pelo qual JS ganhou o "Único idioma que vale a pena tocar na Web do lado do cliente com prêmio". E sim, na verdade houve competição. Eles também são um recurso central do JS. Nós construímos objetos com eles. Tudo tem escopo definido para funções. E eles têm recursos úteis. Podemos examinar os parâmetros através da palavra-chave argumentos. Podemos anexá-los e acioná-los temporariamente no contexto de serem métodos de outros objetos. E eles fazem abordagens orientadas a eventos para coisas obscenamente fáceis de implementar. Em resumo, eles fizeram da JS uma fera absoluta na redução da complexidade e na adaptação de várias implementações da própria JS (mas principalmente da API DOM) diretamente na fonte.
Reavaliar padrões / práticas antes de adotar
Funções de primeira classe e tipos dinâmicos tornam muitos dos padrões de design mais complexos completamente inúteis e pesados em JS. Alguns dos padrões mais simples, no entanto, são incrivelmente úteis e fáceis de implementar, dada a natureza altamente flexível do JS. Adaptadores e decoradores são particularmente úteis e achei os singletons úteis para fábricas de widgets de interface do usuário complexas que também atuam como gerenciadores de eventos para os elementos de interface do usuário que eles constroem.
Siga o exemplo do idioma e faça mais com menos
Acredito que um dos principais especialistas em Java defenda em algum lugar que a verbosidade é realmente um recurso positivo que facilita a compreensão do código para todas as partes. Hogwash. Se isso fosse verdade, o legalese seria mais fácil de ler. Somente o escritor pode tornar mais fácil o que eles escreveram e você pode fazer isso colocando-se no lugar do outro ocasionalmente. Então, adote essas duas regras. 1. Seja o mais direto e claro possível. 2. Chegue ao ponto maldito já. A vitória é que um código conciso e limpo é uma ordem de magnitude mais fácil de entender e manter do que algo em que você precisa atravessar vinte e cinco camadas para ir do gatilho à ação desejada real. A maioria dos padrões que defendem esse tipo de coisa em linguagens mais rígidas são, na verdade, soluções alternativas para limitações que o JavaScript não possui.
Tudo é maleável e tudo bem
JS é provavelmente uma das linguagens menos protecionistas em uso popular. Abrace isso. Funciona bem. Por exemplo, você pode escrever objetos com vars "particulares" persistentes inacessíveis, simplesmente declarando vars regulares em uma função de construtor, e faço isso com freqüência. Mas não é para proteger meu código ou seus usuários "deles mesmos" (eles poderiam substituí-lo por sua própria versão durante o tempo de execução). Mas é um sinal de intenção, porque a suposição é de que o outro cara é competente o suficiente para não querer alterar as dependências e verá que você não pretende chegar diretamente a ela, talvez por um bom motivo.
Não há limites de tamanho, apenas domínios com problemas
O maior problema que tenho com todas as bases de código Java que eu já vi é uma superabundância de arquivos de classe. Antes de tudo, o SOLID é apenas uma reiteração confusa do que você já deve saber sobre OOP. Uma classe deve lidar com um conjunto específico de problemas relacionados. Não há um problema com um método. Isso é apenas pegar o código C de func-spaghetti em encadeamento antigo apenas com a adição de toda a sintaxe de classe inútil para inicializar. Não há limite de tamanho ou método. Se faz sentido adicionar algo a uma função, classe ou construtor já longa, faz sentido. Tome jQuery. É todo um conjunto de ferramentas de tamanho de biblioteca em uma única função e não há nada de errado nisso. Se ainda precisamos do jQuery, o debate é razoável, mas em termos de design,
Se Java é tudo que você sabe, mergulhe em algo com uma sintaxe não baseada em C
Quando comecei a mexer no Python porque gostava do que estava ouvindo sobre o Django, aprendi a começar a separar sintaxe do design de linguagem. Como resultado, ficou mais fácil entender Java e C como uma soma de suas partes de design de linguagem, em vez de uma soma de coisas que eles fazem de maneira diferente com a mesma sintaxe. Um bom efeito colateral é que quanto mais você entender outras linguagens em termos de design, melhor entenderá os pontos fortes / fracos da pessoa que você conhece melhor através do contraste.
Conclusão
Agora, considerando tudo isso, vamos acertar todos os seus pontos-problema:
- Não há maneira imediata de localizar o ponto de entrada de uma função (exceto uma pesquisa de texto sem formatação, que pode resultar em pesquisas subsequentes de métodos além da hierarquia de chamadas, depois de duas ou três das quais você esqueceu por onde começou)
Chrome e Firebug realmente têm rastreamento de chamadas. Mas veja também meus pontos de vista sobre estrutura e manter as coisas concisas e diretas. Quanto mais você pensa no seu aplicativo como construções maiores e bem encapsuladas que interagem entre si, mais fácil é descobrir de quem é a culpa quando as coisas dão errado. Eu diria que isso também é verdade em Java. Temos construtores de função de classe que são perfeitamente reparáveis para preocupações tradicionais de POO.
function ObjectConstructor(){
//No need for an init method.
//Just pass in params and do stuff inside for instantiation behavior
var privateAndPersistent = true;
//I like to take advantage of function hoisting for a nice concise interface listing
this.publicAndPointlessEncapsulationMurderingGetterSetter
= publicAndPointlessEncapsulationMurderingGetterSetter;
//Seriously though Java/C# folks, stop with the pointless getter/setters already
function publicAndPointlessEncapsulationMurderingGetterSetter(arg){
if(arg === undefined){
return privateAndPersistent;
}
privateAndPersistent = arg;
}
}
ObjectConstructor.staticLikeNonInstanceProperty = true;
var instance = new ObjectConstructor();//Convention is to capitalize constructors
No meu código, quase nunca uso os literais de objeto {}
como componentes estruturais de aplicativos, pois eles não podem ter vars internos (privados) e preferem reservá-los para uso como estruturas de dados. Isso ajuda a definir uma expectativa que mantém a clareza de intenção. (se você ver curvas, são dados, não um componente da arquitetura do aplicativo).
- Os parâmetros são passados para funções, sem maneira de saber quais propriedades e funções estão disponíveis nesse parâmetro (além de executar o programa, navegar até o ponto em que a função é chamada e usar console.logs para gerar todas as propriedades acessível)
Mais uma vez, consulte as ferramentas modernas do navegador. Mas também, por que é tão chato executar o programa novamente? Recarregar é algo que um desenvolvedor da Web do cliente normalmente acessa a cada poucos minutos, porque não custa absolutamente nada para fazê-lo. Novamente, outro ponto com o qual a estrutura do aplicativo pode ser útil, mas é uma desvantagem negativa do JS que você precisa executar sua própria validação ao impor contratos é essencial (algo que eu faço apenas nos pontos de extremidade expostos a outras coisas que minha base de código não não controle). Na OMI, a compensação vale bem os benefícios.
- O uso comum de funções anônimas como retornos de chamada, que freqüentemente levam a um espaguete de caminhos de código confusos, pelos quais você não pode navegar rapidamente.
Sim, isso é ruim em qualquer coisa não trivial. Não faça isso. Nomeie suas funções como crianças. É mais fácil rastrear as coisas também. Você pode definir, avaliar (necessário para atribuir) e atribuir uma função trivial simples, alinhada com:
doSomethingWithCallback( (function callBack(){}) );
Agora, o Chrome terá um nome para você quando você estiver rastreando as chamadas. Para funções não triviais, eu o definiria fora da chamada. Observe também que funções anônimas atribuídas a uma variável ainda são anônimas.
- E, com certeza, o JSLint detecta alguns erros antes do tempo de execução, mas mesmo assim não é tão útil quanto ter linhas onduladas vermelhas sob seu código diretamente no navegador.
Eu nunca toco nas coisas. Crockford deu algumas coisas boas à comunidade, mas o JSLint cruza a linha em preferências estilísticas e sugerir que certos elementos do JavaScript são partes ruins por nenhuma razão particularmente boa, IMO. Definitivamente, ignore uma coisa sobre as classes regEx e negation seguidas por * ou +. Os curingas têm um desempenho mais fraco e você pode limitar facilmente a repetição com {}. Além disso, ignore qualquer coisa que ele disser sobre construtores de funções. Você pode envolvê-los facilmente em uma função de fábrica se a nova palavra-chave o incomodar. O CSSLint (não o de Crockford) é ainda pior no que diz respeito aos maus conselhos. Sempre leve as pessoas que fazem muitas palestras com um pouco de sal. Às vezes eu juro que eles estão apenas procurando estabelecer autoridade ou gerar novo material.
E, novamente, você deve desaprender o que aprendeu com essa preocupação em tempo de execução que possui. (é comum que eu já vi muitos desenvolvedores Java / C #). Se os erros em tempo de execução ainda o incomodam 2 anos depois, quero que você se sente e recarregue o spam em um navegador até que ele afunde. não há divisão em tempo de compilação / tempo de execução (de qualquer forma, não é visível - o JS é executado em um JIT agora). Não é apenas bom descobrir bugs em tempo de execução, é extremamente benéfico recarregar spam com facilidade e facilidade e descobrir bugs em todos os pontos de parada.
E descubra essas ferramentas de desenvolvimento do Chrome. Eles são integrados diretamente ao webkit. Clique com o botão direito do mouse no Chrome. Inspecionar elemento. Explore as guias. Existe bastante poder de depuração, com a capacidade de alterar o código no console durante o tempo de execução, sendo uma das opções mais poderosas, mas menos óbvias. Ótimo para testar também.
Em uma nota relacionada, os erros são seus amigos. Nunca escreva uma declaração de captura vazia. Em JS, não ocultamos ou ocultamos erros (ou pelo menos não devemos tossir YUI / tosse ). Nós atendemos a eles. Qualquer coisa menos resultará em dor de depuração. E se você escrever uma instrução catch para ocultar erros em potencial na produção, registre pelo menos silenciosamente o erro e documente como acessar o log.