
Quando eu e meu amigo estávamos em idade escolar e aspiramos a desenvolver desenvolvedores de software, sonhávamos em projetar coisas legais juntos - como um jogo ou um aplicativo mega útil.
Eu escolhi aprender C ++ e C #, ele escolheu JavaScript. Terminamos a escola, nos formamos em nossas universidades, servimos no exército e começamos nossos trabalhos. Tivemos um tempo bastante ocupado em engenharia de software industrial, com muitos empregos e posições diferentes e, depois que tudo começou a nos desgastar, lembramos onde tudo havia começado.
Depois de finalmente nos reunirmos como desenvolvedores maduros, decidimos trabalhar em nosso próprio projeto - um videogame 2D. Como o domínio de meu amigo era front-end e eu era um desenvolvedor de pilha completa, nossa escolha imediata da plataforma de desenvolvimento foi um navegador da Internet. Como eu estava acostumado a trabalhar com o TypeScript ao projetar o front-end, pensamos que tudo bem, afinal, o TS é apenas JavaScript em escala. Vamos usá-lo e as coisas correrão bem. Se eu soubesse o quão errado eu estava! Quando começamos a discutir o projeto, encontramos um abismo extenso de mal-entendidos entre nós.
Aqui estava a minha visão do jogo. Eu estava tipo, ok, temos tipos como jogo, ferramenta, item, mapa, localização. Eu tenho um entendimento básico de como eles funcionam juntos, então eu os descrevo, compilo o projeto - e ele funciona. Afinal, o compilador verificou meu código e eu fiz isso corretamente. Em seguida, começo a escrever o código que usa esses tipos. Eles tornam minha vida muito mais fácil. Meu IDE fornece dicas de ferramentas e verifica se há erros. Se um projeto puder ser compilado, provavelmente funcionará. Eu gastei algum esforço na descrição do tipo e ele produziu resultados. Essa é a minha abordagem em poucas palavras.
Meu amigo teve a ideia oposta - pular para a codificação imediatamente, sem ter tempo para descrever os tipos. Ele não estava pronto para definir o problema como uma família de tipos. Ele não estava interessado em usá-lo como base, pois não via o problema como um conjunto de classes, tipos, registros de qualquer coisa do tipo. Eu pensei que era inconcebível. Nós dois tínhamos razão, mas nossos pontos eram mutuamente exclusivos.
Sério, estávamos conversando por horas, mas cada um estava dizendo o que queria, como se estivéssemos falando idiomas diferentes. Veja bem, eu não poderia culpar o fato de estarmos presos aos nossos velhos hábitos. Há apenas um ano, migrei sem problemas do mundo da programação orientada a objetos para o mundo da programação funcional e vice-versa. Além disso, passei um bom tempo aprendendo JS, e ele - aprendendo várias linguagens estaticamente tipadas.
No entanto, para qualquer desenvolvedor, a tecnologia que eles usaram para seu primeiro trabalho real geralmente os define na medida em que dois adultos experientes simplesmente não têm paciência para ouvir um ao outro. Ao longo desses anos de engenharia de software, nossas visões foram moldadas de maneiras tão diferentes que nossas abordagens para a solução de problemas simplesmente não se encaixavam bem.
No final, abandonamos a ideia de trabalhar em equipe. Sua primeira resposta pode ser que o problema estava em nossas personalidades. Você pode estar certo, mas também vi isso acontecer com outras pessoas do setor.
A diferença fundamental e inconciliável entre a digitação estática e a dinâmica
Meu código fornece a solução para o problema de como trabalhar com ele, enquanto o código de advogados de digitação dinâmica experientes resolve o problema de como ele funciona. Ambas as mentalidades são legítimas e suportadas pelas ferramentas existentes, mas apenas uma pode ter a maior prioridade a qualquer momento.
A digitação estática é boa para projetos de grande escala que envolvem centenas de desenvolvedores que trabalham com eles há anos, enquanto a digitação dinâmica é boa para equipes e projetos menores que geralmente exigem código somente de gravação. A digitação dinâmica permite economizar tempo e esforços no início do desenvolvimento, enquanto a digitação estática oferece um impulso no final.
A idéia de colocar os tipos em primeiro lugar afetou seriamente o meu pensamento como desenvolvedor. Depois de escolher o C # no início da minha carreira, tenho uma digitação estática codificada na minha mentalidade e estou pagando o preço dessa inflexibilidade agora. Quando vejo uma tarefa, tento imaginar sua solução como um conjunto de tipos e regras de seu relacionamento. Quando estou desenvolvendo um módulo, meu primeiro passo é definir os tipos que ele opera e usa para interagir com seu ambiente. Só não me lembro de como costumava resolver problemas antes disso.
Todo o processo de aprender a programar em Java é sobre aprender a projetar e usar tipos. O .NET CLR - o tempo de execução do C # - é baseado em tipos e por tipos. A digitação estática está no centro do paradigma de programação orientada a objetos (Olá, classes JS, decidi dar um tempo). As implementações canônicas da maioria dos padrões de OOP estão saturadas com a palavra-chave Interface, que não faz nenhum sentido em uma linguagem de tipo dinâmico.
Os próprios padrões de design são conceitos de linguagem cruzada, mas alguém pode me dizer por que diabos eu precisaria do padrão de Estado em uma linguagem de tipo dinâmico? E o Builder? Esses padrões não têm nada a ver com desenvolvimento, eles são principalmente sobre tipos. Tipos e POO têm um vínculo estreito.
Você não pode construir sua lógica de negócios em tipos e ainda não sabe nada sobre eles ao começar a escrever código. É por isso que temos desenvolvedores de front-end que armam seu código com um número incrível de testes de unidade que verificam especificamente a base de código quanto a erros de tipo.
Todos sabemos que a proteção baseada na cobertura do código é uma ilusão. Os testes são escritos manualmente e, por definição, são menos confiáveis do que o sistema interno de verificação de tipo disponível no idioma.
Isso não significa que linguagens dinamicamente digitadas não fazem sentido (embora eu confesse que acho que não). Isso significa que, ao usá-los, você precisa se afastar do OOP como o paradigma dominante. Toda essa unidade de dados e operações orientadas a dados é para companheiros que possuem digitação estática.
Os desenvolvedores que eu encontrei não acham que a digitação estática afeta a maneira de codificar, então eles apenas escrevem seu código como se estivessem usando uma linguagem dinâmica, apenas adicionam verificação de tipo. Eu acredito que isso é inerentemente errado. É especialmente óbvio no caso do front-end moderno.
Eu sei, eu sei, há um tabu em criticar os desenvolvedores de front-end. Meu amigo e eu uma vez montamos um bot de inteligência artificial que controlava os usuários do Twitter, e nós brendamos com Brendan Eich. Sério, o criador do JavaScript teve um retorno com a nossa rede neural nos comentários.
Por alguma razão, esses caras simplesmente não estão prontos para viver em um mundo onde sua visão tem deficiências tangíveis. É por isso que critico apenas aqueles que mexem no meu projeto definitivamente digitado para retrabalhá-lo da maneira descontraída "qualquer".
Nós continuaríamos morando em nossos minúsculos mundos, mas o TypeScript nos uniu
Veja-me, por exemplo: por causa das restrições de tipo, meu código é impossível de usar incorretamente. Quando estou trabalhando em um projeto, confio em outras pessoas para usar tipos também. Então meu código funcionará exatamente como projetado. Portanto, eu deliberadamente não abordo todos os casos em que esse código pode ser usado incorretamente (porque a digitação o torna impossível). Mas um desenvolvedor JS ingressa no meu projeto, pega meu tipo, agrupa-o em Qualquer e começa a usá-lo incorretamente, o que resulta em bugs difíceis de replicar.
Os desenvolvedores de JavaScript estão confiantes de que o TypeScript é o mesmo JS antigo, mas com uma opção para adicionar verificações de tipo estáticas, caso precisem delas. Isto está errado. O TypeScript é cem vezes mais poderoso, mas eles só estão interessados em uma fração do seu potencial.
O argumento deles é que o TypeScript é apenas um superconjunto de JS. Na prática, não se pode ignorar o fato de que o TypeScript é uma linguagem independente, mesmo que se trate de um rei do front-end. Porque requer uma abordagem diferente - a verificação estática, não dinâmica.
O principal benefício da digitação estática é que ela oferece garantias. Se você o usar em um módulo e optar por não usá-lo em outro, então você desperdiçará seu tempo e energia descrevendo e projetando esses tipos, sem obter nenhuma garantia.
Muitos pensam que o TypeScript é um compromisso dos sistemas de tipos entre JS e Java. Bem, não é um compromisso de nenhum tipo, ele tem um sistema de tipos especial próprio.
O pior de tudo é que hoje em dia, uma em duas posições de front-end exige proficiência no TypeScript. Isso estimula os desenvolvedores de JS a dar uma olhada nos recursos do TypeScript e imediatamente começar a escrever o código nele, gerando uma proliferação de práticas prejudiciais. As situações ocorrem quando elas realmente não precisam de verificação estática de tipo, mas isso foi meio que imposto a elas, então elas mexeram com ela. Finalmente, precisamos reconhecer que as abordagens de programação com tipagem estática versus dinâmica estão em conflito entre si e não podem ser misturadas.
Eu vejo o JavaScript como uma ótima ferramenta para escrever código de hack rápido, que fornece soluções sem resolver abstrações desnecessárias. O exemplo mais ultrajante aqui é o padrão da Fábrica de Gelo. Você pode alimentar suas instâncias e envolverá-as na imutabilidade do tempo de execução. Se eu processar meu objeto através dessa fábrica, ele retornará seu equivalente, mas se eu tentar alterar uma de suas propriedades, ele lançará uma exceção. WAT?!?
O padrão surgiu porque os desenvolvedores de front-end ouviram algo sobre imutabilidade legal, então eles decidiram arrastar essa merda para o idioma deles, que precisa disso como um buraco na cabeça. No TypeScript, eu posso projetar uma fábrica semelhante, mas com uma restrição de tempo de compilação para mutações e sem nenhuma exceção.
Por outro lado, dificilmente preciso disso porque existe a programação funcional pura. Tomemos, por exemplo, F #, Haskell, OCaml, Clojure, ReasonML - eles têm uma proibição imediata de mutabilidade. Mas algo me diz que, se um desenvolvedor front-end colocar as mãos em uma linguagem funcional, ele estará disposto a atualizá-la para tornar seu comportamento semelhante ao do JavaScript.
Isso porque escolher sua religião de digitação é uma passagem só de ida. Todas as soluções fornecem apenas uma ilusão de compromisso. Você depende de tipos ou não. Não sei se minha vida seria diferente se eu tivesse começado a aprender C # e JavaScript em paralelo. Hoje, estou tão desesperadamente me identificando com minha mentalidade que simplesmente não vejo nenhuma vantagem da digitação dinâmica (e não desejo vê-las). Eles existem, apenas fora do meu alcance de visibilidade, então tudo o que posso fazer é fechar os olhos para eles, assim como faço para qualquer fenômeno que eu tenha que suportar neste mundo. Sei que estou errado, mas tenho que trabalhar aqui e agora e não tenho orçamento para ficar sentado em cima do muro.
Portanto, não quero procurar compromissos, em vez disso, vou esclarecer as coisas. Se você está apenas dando os primeiros passos no desenvolvimento, comece com a digitação estática!