De um tradutor: este artigo é uma tradução do
material escrito pelo programador
Alastair Paragas da Apple e trabalhou com linguagens de programação como Javascript, Python, PHP, Java, Scala, Haskell, Swift e Rust. Alastair compartilha seus pensamentos sobre o tema de escolher e aprender o idioma "his", porque esse problema é relevante para iniciantes e profissionais que desejam escolher um novo kit de ferramentas.
Se você está aprendendo uma linguagem de programação por motivos de emprego ou treinamento avançado, ou é apenas um hobby, mais cedo ou mais tarde você terá que escolher entre elas. Como fazer isso? A pergunta não é simples, mas a resposta é: milhares de programadores fazem isso todos os dias. Para facilitar sua tarefa, vale a pena seguir alguns princípios.
A Skillbox recomenda: Curso prático "Profissão Web Developer" .
Lembramos que: para todos os leitores de Habr - um desconto de 10.000 rublos ao se inscrever em qualquer curso Skillbox de acordo com o código promocional Habr
.
Indicadores comparativos
Níveis de abstraçãoSe fortemente generalizado, podemos dizer que as linguagens de programação modernas são divididas em três tipos:
- "Rápido", usado para criar rapidamente aplicativos ou seus protótipos.
- "Infra-estrutura", que ajuda a otimizar ou modificar partes de um aplicativo já gravado para aumentar sua produtividade.
- As chamadas linguagens de programação do sistema, cujo uso permite que você obtenha controle completo sobre a memória do dispositivo.
Obviamente, a verdadeira separação de tipos entre linguagens de programação é menos rigorosa: existem variantes intermediárias e híbridas de vários tipos.
Se falamos sobre o aprendizado de idiomas, primeiro você deve tentar o primeiro tipo - idiomas "rápidos": eles permitem que você veja imediatamente o resultado do trabalho e aprenda com seus próprios erros. Estes são principalmente PHP, Javascript, Ruby e Python. O limite de entrada aqui é mínimo e você pode aprender o básico em pouco tempo. Essas linguagens possuem bibliotecas padrão que permitem adicionar um grande número de funções ao aplicativo, e o alcance de seus recursos é bastante grande.
from concurrent.futures import ThreadPoolExecutor from http.client import HTTPException from urllib import request from typing import Union, Dict, Any, List def get_request_task(url: str) -> Union[List[Dict[str, Any]], None]: try: contents = None with request.urlopen(url) as response: contents = response.read() return contents except HTTPException: return None with ThreadPoolExecutor() as executor: for result in executor.map(get_request_task, [ "https://jsonplaceholder.typicode.com/posts", "https://jsonplaceholder.typicode.com/comments", "https://jsonplaceholder.typicode.com/albums" ]): if result is None: print("Something terrible has happened!") else: print(result)
Implementando solicitações HTTP multithread em Python com digitação estática. O multithreading oferece a possibilidade de alternar três tarefas (vamos chamá-las de tarefas A, B e C). Enquanto uma tarefa (digamos, tarefa A) executa alguma operação relacionada à E / S (e, portanto, não executa nenhum trabalho de cálculo), outras tarefas são executadas simultaneamente com ela.Quanto às linguagens de "infraestrutura", essas são Java, Kotlin, Scala, Clojure, além de GoLang, Swift e Haskell. Você pode chamá-los de maneira conveniente, mas eles permitem que você crie aplicativos produtivos. As complexidades incluem menos elementos prontos para uso, sintaxe precisa, etc. Esses idiomas são bons porque permitem ajustar o aplicativo. Se você precisar de velocidade, tente escrever um aplicativo em um deles.
import Foundation import Dispatch func getRequestTask(url: String, dispatchGroup: DispatchGroup) { dispatchGroup.enter() let request = URLRequest(url: URL(string: url)!) let task = URLSession(configuration: URLSessionConfiguration.default).dataTask( with: request, completionHandler: { (data, response, error) in if let data = data { if let dataAsString = String(data: data, encoding: .utf8) { print(dataAsString) dispatchGroup.leave() return } } print("Something terrible has happened!") dispatchGroup.leave() } ) task.resume() } let requestDispatchGroup = DispatchGroup() for url in [ "https://jsonplaceholder.typicode.com/posts", "https://jsonplaceholder.typicode.com/comments", "https://jsonplaceholder.typicode.com/albums" ] { getRequestTask(url: url, dispatchGroup: requestDispatchGroup) } requestDispatchGroup.wait()
Um problema semelhante já foi resolvido acima usando Python. Agora nos negócios - Swift.Linguagens de programação do sistema - C, C ++, Rust. Eles fornecem controle máximo sobre o aplicativo, incluindo gerenciamento de memória. Além disso, essas linguagens são ótimas para programar microcontroladores, computadores com arquitetura de processador personalizada e outros sistemas. Os idiomas de baixo nível ainda são importantes e provavelmente continuarão relevantes no futuro próximo.
FuncionalidadeComo você sabe, os idiomas servem como um meio de "comunicação" entre um computador e um programador. Para que essa comunicação ocorra sem problemas, vale a pena estudar a sintaxe do idioma em detalhes. Em particular, um especialista deve conhecer as estruturas de dados mais usadas e entender como modificar certos elementos de sua aplicação.
module Main where import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.Resource (runResourceT) import Data.Conduit (($$+-), ($=+), runConduit) import Data.Conduit.List (mapM_, map, filter, catMaybes) import Data.Text (unpack) import Data.Maybe (fromJust) import Web.Twitter.Types (StreamingAPI(SStatus, SRetweetedStatus) , Status(Status), statusText, statusLang , RetweetedStatus(RetweetedStatus), rsRetweetedStatus ) import Web.Twitter.Conduit.Stream (stream)
Haskell é uma linguagem de programação funcional estrita. Ele pode verificar as estruturas de dados recebidas e trabalhar com elas se elas atenderem a certos requisitos.
Tempo de execução - você precisa saber como seu aplicativo funcionará em vários sistemas. É necessário um intérprete de linguagem (por exemplo, Python, NodeJS, PHP)? É gerado um binário dependente do sistema (por exemplo, Swift e GoLang)? O idioma selecionado usa uma combinação das primeira e segunda opções, por exemplo, o aplicativo é compilado e iniciado em alguma máquina virtual (Java, Scala, Clojure)?
A propósito, no caminho da excelência, é altamente recomendável estudar e começar a usar o Docker plus para garantir a compreensão dos princípios de administração do Linux.
Bibliotecas - cada idioma é adequado em determinadas situações. Por exemplo, Java atende a muitos dos requisitos de orquestração e logística de rede, incluindo suporte ao banco de dados por meio da padronização da interface JDBC e projetos como os que são abrangidos pelo suporte da Apache Foundation. O mesmo vale para Python - é ideal para análise de dados e cálculos estatísticos - assim como para Haskell com suas gramáticas, expressões regulares e compiladores. A popularidade da linguagem e o tamanho de sua comunidade são mais dois argumentos que falam a favor do uso de uma certa ferramenta de programação em seu projeto. Se a comunidade é pequena, você não deve contar com a assistência de ambulância de seus participantes. E vice-versa, quanto maior a comunidade e mais popular a linguagem de programação, mais rápido você pode resolver uma tarefa difícil ou obter conselhos de colegas.
Coleta de lixoA coleta de lixo é uma forma de gerenciamento automático de memória. Um processo especial chamado coletor de lixo periodicamente libera memória ao excluir objetos que não são mais necessários pelos aplicativos. Cada linguagem de programação faz isso da sua maneira.
O Python implementa a contagem de referências por meio do algoritmo stop-the-world. Interrompe a execução do programa, inicia e executa a coleta de lixo e retoma o processo principal. Durante a “limpeza”, três “gerações” separadas aparecem - um conjunto de “pilhas de lixo”. Zero contém os objetos "mais recentes", depois as gerações 1 e 2.
import gc import ctypes gc.set_debug(gc.DEBUG_SAVEALL) class PyObject(ctypes.Structure): _fields_ = [("refcnt", ctypes.c_long)] object1 = {} object2 = {} object3 = {} object1['reference_to_2'] = object2 object2['reference_to_1'] = object1 object3['some_key'] = 1 object1_memory_address = id(object1) object2_memory_address = id(object2) object3_memory_address = id(object3) print "Before garbage collection --->" print "Refcount for object1: {count}".format( count=PyObject.from_address(object1_memory_address).refcnt ) print "Refcount for object2: {count}".format( count=PyObject.from_address(object2_memory_address).refcnt ) print "Refcount for object3: {count}".format( count=PyObject.from_address(object3_memory_address).refcnt ) del object1, object2, object3 gc.collect() print "After garbage collection --->" print "Refcount for object1: {count}".format( count=PyObject.from_address(object1_memory_address).refcnt ) print "Refcount for object2: {count}".format( count=PyObject.from_address(object2_memory_address).refcnt ) print "Refcount for object3: {count}".format( count=PyObject.from_address(object3_memory_address).refcnt ) print "Objects that cannot be cleaned up by reference counting: --->" for x in gc.garbage: print x
Implementação do coletor de lixo Python
Os resultados do código do programa acimaO PHP (começando com a versão PHP5.3) usa outra opção de coleta de lixo junto com a contagem de referências. Aqui, esse processo, se necessário, é realizado em conjunto com o programa. Os subgráficos que não podem ser alcançados a partir da raiz são eliminados.
Swift também usa contagem de referência; não há outras maneiras de coletar lixo. O caso é mostrado abaixo quando o contador "forte" do objeto atinge totalmente 0 e limpa Person (uma vez que está fracamente correlacionado com Apartment).
class Person { let name: String init(name: String) { self.name = name } var apartment: Apartment? deinit { print("\(name) is being deinitialized") } } class Apartment { let unit: String init(unit: String) { self.unit = unit } weak var tenant: Person? deinit { print("Apartment \(unit) is being deinitialized") }

Existem muitos exemplos de mecanismos de coleta de lixo implementados em outros idiomas. Eles podem afetar o desempenho geral do aplicativo ou trabalho sem afetar a execução da tarefa principal.
Conceitos duplicados
Criando e gerenciando pacotesFamiliarize-se com os mecanismos de armazenamento e rastreamento de dependências, bem como maneiras de manter informações sobre o "assembly" (descrição do pacote, como executar testes de unidade, configurar e preparar o ambiente etc.).
Python usa
pip em conjunto com um arquivo requirements.txt para gerenciar dependências e
setup.py para gerenciar configurações do ambiente , Haskell trabalha com o
Cabal para resolver ambos os problemas, Java possui
Maven e
Gradle , no caso do Scala
SBT funciona, o PHP usa o
Composer , NodeJS -
npm etc.
Certifique-se de decidir sobre a localização do ambiente de desenvolvimento - você pode querer executar versões diferentes das linguagens de programação, dependendo do projeto. Phpbrew para PHP, pyenv para Python e nvm para NodeJS tornam isso possível.
Usando pyenv, você pode trabalhar com diferentes versões do Python.Em casos especiais, acontece que a biblioteca usada em um projeto é instalada automaticamente em outros. Isso é verdade, em particular, para idiomas como Python e Haskell. Para evitar esse problema, você deve usar
virtualenv / venv para Python,
virtphp para PHP e
Cabal Sandboxes para Haskell.
Entrada / saída assíncronaEsta é uma oportunidade para aumentar o desempenho de E / S dos dados do aplicativo. Ao mesmo tempo, cada thread trabalha com seu próprio conjunto de registros e empilha informações.

const https = require("https"); const urlList = [ "https://reqres.in/api/users?page=1", "https://reqres.in/api/users?page=2", "https://reqres.in/api/users?page=3" ]; function getSiteContents(url) { return new Promise(function (resolve, reject) { https.get(url, function (res) { var bodyData = ""; res.on("data", function (chunk) { bodyData += chunk; }); res.on("end", function () { resolve(bodyData); }); res.on("error", function (error) { reject(error.message); }); }); }); }
Implementando E / S assíncrona usando JavascriptProgramação funcionalA programação funcional permite "dizer" ao computador em alto nível o que você realmente deseja dele. Hoje, a maioria dos idiomas possui os recursos mais básicos para implementar isso: através de
mapa ,
filtro ,
redução de listas , etc. Mas ainda vale a pena usar. Abaixo está um exemplo de programação funcional em uma linguagem que não parece implicar essa possibilidade.
<?php
Treinamento
A primeira etapa é a busca pelas informações necessárias sobre recursos especializados e a criação de um pequeno projeto após a conclusão do treinamento básico. Na maioria dos casos, você pode usar artigos como "Aprenda X em Y Days", muitos dos quais são muito bons. Em muitos casos, existem exemplos de treinamento interativo:
Um tour pelo GoLang e
GoLang por exemplo (para GoLang),
exercícios de linha de comando do NodeSchool (para Javascript, ou seja, NodeJS),
exercícios Scala (para Scala),
Python Koans (para Python) e assim por diante. .p.
Começando com algo complicado não vale a pena. Criar pequenos aplicativos e scripts é o que um iniciante precisa. O número total de linhas de código nessas experiências não excede 300 a 400. O principal que é necessário nesse estágio é obter informações básicas, aprender a programar a qualquer velocidade normal e o mais importante é entender o que você está fazendo.
func containedClosureIncrementer() -> (() -> Int) { var anInt = 0 func incrementer() -> Int { anInt = anInt + 1 return anInt } return incrementer } func containedClosureIncrementer2() -> () -> Int { var anInt = 0 return { anInt = anInt + 1 return anInt } } let closureIncrementer = containedClosureIncrementer() print("containedClosureIncrementer call - should be 1: \(closureIncrementer() == 1)") print("containedClosureIncrementer call - should be 2: \(closureIncrementer() == 2)") var someOptionalValue: Optional<String> = nil; print("Optional - someOptionalValue is null: \(someOptionalValue == nil)") someOptionalValue = "real value" print("Optional - someOptionalValue is 'real value' \(someOptionalValue == "real value")") (["real value", nil] as Array<Optional<String>>).forEach({ someOptionalValue in if let someValue = someOptionalValue { if someValue.hasPrefix("real") { print("someValue: has real") } else { print("someValue: doesn't have real") } } else { print("someValue: has nil") } }) if (someOptionalValue ?? "").hasPrefix("real") { print("Has real 2") } else { print("Doesn't have real") } let numbersList: [Int] = Array(1...10) print("List of numbers 1 to 10: \(numbersList)") let numbersListTimes2 = numbersList.map({ (someNumber: Int) -> Int in let multiplicand = 2 return someNumber * multiplicand }) let numbersListTimes2V2 = numbersList.map({ number in number * 2 }) let numbersListTimes2V3 = numbersList.map { $0 * 2 } print("List of numbers * 2: \(numbersListTimes2)") print("V1, V2 Map operations do the same thing: \(numbersListTimes2 == numbersListTimes2V2)") print("V1, V3 Map operations do the same thing: \(numbersListTimes2 == numbersListTimes2V3)") func testGuard() { let someOptionalValue: Optional<String> = nil; guard let someOptionalValueUnwrapped = someOptionalValue else { print("testGuard: Thrown exception - nil value") return } print("testGuard: no exception - non-nil value: \(someOptionalValueUnwrapped)") } testGuard() class RuntimeError: Error {} [{throw RuntimeError()}, {1} as () throws -> Int].forEach { let returnValue = try? $0() if let returnValueUnwrapped = returnValue { print("List of closures: A normal value was returned \(returnValueUnwrapped)") } else { print("List of closures: An error was thrown") } }
Um exemplo de script inicial que dá uma idéia para um programador iniciante sobre como seu código funcionaA segunda etapa é um estudo mais aprofundado da linguagem, a criação de um projeto completo, que não pode mais ser chamado de "infantil". Em muitos casos, você precisa se familiarizar com a documentação oficial. Para Javascript, é o
Mozilla Developer Docs , para Swift,
Swift Official Docs , para Java,
Java Learning Trails , para Python,
Python Official Docs t. Atenção especial deve ser dada aos cursos on-line com bons professores.
Também vale a pena explorar outros projetos de código aberto. Recursos como a
fonte Annotated jQuery ou a
fonte Annotated BackboneJS dão uma idéia de como uma linguagem de programação específica e bibliotecas adicionais são usadas em projetos profissionais.
Tudo isso ajudará a criar seu próprio projeto sério, por exemplo, um aplicativo de desktop, um aplicativo da web, um programa móvel. Tente usar bibliotecas externas quando precisar de ferramentas e funções adicionais.

Não se esqueça do desempenho do seu aplicativo, tente sempre extrair informações das fontes mais recentes. As oportunidades de aprendizado são infinitas, você pode melhorar para sempre. Mas, no final, você pode sentir que se tornou um profissional desde iniciante - e simplesmente não há sentimento melhor no mundo.
A Skillbox recomenda: