Como um aumento na complexidade dos sistemas afetou sucessivas gerações de programadores?

127

Como programador "novo" (escrevi uma linha de código pela primeira vez em 2009), notei que é relativamente fácil criar um programa que exiba elementos bastante complexos hoje com coisas como o .NET framework, por exemplo. A criação de uma interface visual ou a classificação de uma lista podem ser feitas com muito poucos comandos agora.

Quando eu estava aprendendo a programar, também estava aprendendo a teoria da computação em paralelo. Coisas como algoritmos de classificação, princípios de como o hardware opera juntos, álgebra booleana e máquinas de estado finito. Mas notei que, se eu quisesse testar algum princípio muito básico que aprendi na teoria, era sempre muito mais difícil começar, porque muita tecnologia é obscurecida por coisas como bibliotecas, estruturas e o sistema operacional.

A criação de um programa com eficiência de memória foi exigida há 40/50 anos, porque não havia memória suficiente e era cara; portanto, a maioria dos programadores prestava muita atenção aos tipos de dados e como as instruções seriam tratadas pelo processador. Atualmente, alguns podem argumentar que, devido ao maior poder de processamento e memória disponível, essas preocupações não são uma prioridade.

Minha pergunta é se os programadores mais antigos vêem inovações como essas como uma dádiva de Deus ou uma camada adicional para abstrair, e por que eles pensam assim? E os programadores mais jovens beneficiam mais o aprendizado de programação de baixo nível ANTES de explorar os domínios das bibliotecas expansivas? Se sim, por que?

Adão
fonte
24
O artigo de Joel Spolsky de 2002 é relevante: joelonsoftware.com/articles/LeakyAbstractions.html Como frase / formulada, no entanto, essa pergunta pode acabar sendo considerada principalmente baseada em opiniões.
precisa saber é
Lamento a falta de opções mais simples para explorar técnicas de programação muito básicas.
GrandmasterB
11
Isso é relevante. Tipo de. (Quer dizer, eu espero que a imagem é uma piada, mas com um pouco do que recebe para StackOverflow ...)
Izkata
11
Tem seus prós e contras. Isso abre o mundo da programação para muitos programadores novos, que não precisam de muita habilidade para ter sucesso - ao contrário do que algumas pessoas dizem, isso é uma coisa boa. E ainda estamos escrevendo programas eficientes, que nunca mudam - é só que os objetivos mudaram. Salvar um byte em um ano não é mais uma coisa boa - é improvável que a diferença de memória faça a diferença e use, por exemplo. dois bytes é mais flexível e à prova de futuro. O custo dos programadores versus o custo do SW e HW também é um fator significativo. A demanda por novos softwares é enorme. Os codificadores são poucos.
Luaan 16/01
11
A escala de tempo de 40/50 anos está incorreta. A programação com eficiência de memória ainda era extremamente importante no Windows de 16 bits (menos de 20 anos atrás) e (infelizmente) na maioria dos robôs incorporados / robóticos atualmente.
David.pfx

Respostas:

174

simplesmente não é necessário devido ao aumento da capacidade de processamento e memória disponível.

Ter memória barata, discos enormes e processadores rápidos não é a única coisa que liberou as pessoas da necessidade de ficar obcecadas com todos os bytes e ciclos. Os compiladores agora são muito, muito melhores que os humanos na produção de código altamente otimizado quando necessário.

Além disso, não vamos esquecer o que realmente estamos tentando otimizar, que é o valor produzido por um determinado custo. Programadores são muito mais caros que máquinas. Tudo o que fazemos que faz com que os programadores produzam programas funcionais, corretos, robustos e com todos os recursos mais rápidos e baratos leva à criação de mais valor no mundo.

Minha pergunta, porém, é como as pessoas se sentem sobre esse "esconderijo" dos elementos de nível inferior. Os programadores mais antigos veem isso como uma dádiva de Deus ou uma camada desnecessária para passar?

É absolutamente necessário realizar qualquer trabalho. Escrevo analisadores de código para viver; se eu precisasse me preocupar com alocação de registro ou agendamento de processador ou qualquer um desses milhões de outros detalhes, não gastaria meu tempo corrigindo bugs, revisando relatórios de desempenho, adicionando recursos e assim por diante.

Toda a programação trata de abstrair a camada abaixo de você para criar uma camada mais valiosa sobre ela. Se você criar um "diagrama de camadas" mostrando todos os subsistemas e como eles são construídos, você verá que existem literalmente dezenas de camadas entre o hardware e a experiência do usuário. Acho que no diagrama de camadas do Windows há algo como 60 níveis de subsistemas necessários entre o hardware bruto e a capacidade de executar o "hello world" em C #.

Você acha que os programadores mais jovens se beneficiariam mais com a programação de baixo nível ANTES de explorar os domínios das bibliotecas expansivas?

Você enfatiza ANTES, portanto, devo responder sua pergunta de forma negativa. Estou ajudando um amigo de 12 anos a aprender a programar agora e é melhor acreditar que estou iniciando-o no Processing.js e não no x86 assembler. Se você começar um jovem programador em algo como Processing.jsele estará escrevendo seus próprios jogos de tiro em cerca de oito horas. Se você os iniciar no assembler, eles multiplicarão três números juntos em cerca de oito horas. Qual você acha que tem mais probabilidade de atrair o interesse de um programador mais jovem?

Agora, se a pergunta é "os programadores que entendem a camada n do bolo se beneficiam da compreensão da camada n-1?" a resposta é sim, mas isso é independente da idade ou da experiência; sempre é possível melhorar sua programação de nível superior entendendo melhor as abstrações subjacentes.

Eric Lippert
fonte
12
Citação divertida +1: Dunbars Number é um bom exemplo (existem outros) de quocientes de capacidade cognitiva estudados que podem ser vistos em muitas pessoas, mostrando que temos um espaço mental fixo. Abstrair várias coisas em generalizações singulares é a única maneira pela qual podemos aumentar de forma coesa o número de coisas em nosso espaço mental, e é disso que a programação de nível superior procura tirar proveito.
precisa
18
@Euphoric: Sua pergunta faz sentido, mas onde você para? Suponha que eu diga "bem, em vez de aprender o Processing.js, vamos aprender a escrever videogames em C ++ usando o DirectX". OK, tudo bem. Agora, o que impede você de dizer "isso não criará problemas se eles quiserem fazer algo menos abstrato?" e, portanto, talvez desejemos começar como escrever um driver de placa gráfica. Mas então você faz a pergunta novamente e, antes que você perceba, estamos inserindo o código da máquina em um Altair com comutadores. Você precisa escolher um nível de abstração em algum lugar !
Eric Lippert
35
@Euphoric: Você faria o mesmo argumento para, digamos, contabilidade? Não precisamos de mais pessoas que possam guardar os livros simples para uma nova empresa de pequeno porte; precisamos de ótimos contadores de classe mundial. Se os cursos introdutórios de contabilidade são tão difíceis que assustam as pessoas que simplesmente aspiram ser produtivas e contadoras, BOM. Não precisamos dessas pessoas no setor de contabilidade! E os pianistas? Se as lições introdutórias de piano assustam as pessoas que não serão ótimas pianistas, isso é bom; nós queremos apenas grandes pianistas no mundo. Algo parece errado com esse argumento?
Eric Lippert
25
@Euphoric: A resposta curta é BOM CÉU SIM, precisamos de programadores mais decentes! Precisamos de mais programadores em todos os níveis de habilidade e experiência. O mundo roda em software . Quanto mais as pessoas que têm qualquer compreensão de como fazer o seu trabalho mundo, melhor.
Eric Lippert
6
@Euphoric (e outros) - estamos meio que atingindo o limite referente à construtividade dos comentários. Junte-se a nós no bate-papo de engenharia de software se você quiser continuar esta conversa.
50

Eu tinha idéias sobre esse assunto e as coloquei em um livro há 20 anos . Está muito esgotado, mas você ainda pode se acostumar com cópias na Amazon .

Uma resposta simples para sua pergunta é tão antiga quanto Aristóteles: a natureza abomina o vácuo . Por mais que as máquinas se tornem mais rápidas e maiores, o software se torna mais lento e maior.

Para ser mais construtivo, o que propus foi que a teoria da informação e sua relevância direta para o software fizessem parte da educação em ciência da computação. Só é ensinado agora, se é que existe, de uma maneira muito tangencial.

Por exemplo, o comportamento big-O dos algoritmos pode ser entendido de maneira muito clara e intuitiva se você pensar em um programa como um canal de informações do tipo Shannon, com símbolos de entrada, símbolos de saída, ruído, redundância e largura de banda.

Por outro lado, a produtividade de um programador pode ser entendida em termos semelhantes usando a teoria da informação de Kolmogorov. A entrada é uma estrutura conceitual simbólica na sua cabeça e a saída é o texto do programa que sai pela ponta dos seus dedos. O processo de programação é o canal entre os dois. Quando o ruído entra no processo, ele cria programas inconsistentes (bugs). Se o texto do programa de saída tiver redundância suficiente, poderá permitir que os erros sejam capturados e corrigidos (detecção e correção de erros). No entanto, se é muito redundante, é muito grande e seu tamanho, combinado com a taxa de erro, causa a introdução de bugs. Como resultado desse raciocínio, passei boa parte do livro mostrando como tratar a programação como um processo de design de linguagem., com o objetivo de definir os idiomas específicos do domínio apropriados para uma necessidade. Nós prestamos atenção às linguagens específicas de domínio na educação em CS, mas, novamente, é tangencial.

Construir idiomas é fácil. Toda vez que você define uma função, classe ou variável, você está adicionando vocabulário ao idioma em que começou, criando um novo idioma com o qual trabalhar. O que geralmente não é apreciado é que o objetivo deve ser tornar a nova linguagem mais próxima da estrutura conceitual do problema. Se isso for feito, ele terá o efeito de encurtar o código e torná-lo menos problemático, simplesmente porque, idealmente, existe um mapeamento 1-1 entre conceitos e código. Se o mapeamento for 1-1, você pode cometer um erro e codificar um conceito incorretamente como um conceito diferente, mas o programa nunca trava, o que acontece quando ele não codifica nenhum requisito consistente .

Nós não estamos entendendo isso. Em toda a nossa conversa corajosa sobre design de sistema de software, a proporção de código para requisitos está aumentando, muito maior.

É verdade, temos bibliotecas muito úteis. No entanto, acho que devemos ser muito cautelosos com a abstração. Não devemos assumir que B se baseia em A e isso é bom, que se C se baseia em B, é ainda melhor. Eu chamo isso de fenômeno "princesa e ervilha". Empilhar camadas sobre algo problemático não necessariamente o corrige.

Para encerrar um longo post, desenvolvi um estilo de programação (que às vezes me causa problemas) em que

  • Invenção não é uma coisa ruim. É uma coisa boa, como em outros ramos da engenharia. Claro que pode estar criando uma curva de aprendizado para outras pessoas, mas se o resultado geral for uma melhor produtividade, vale a pena.
  • Código minimalista no estilo haicai. Isso vale principalmente para o design da estrutura de dados. Na minha experiência, o maior problema em software atualmente é a estrutura de dados inchada.
Mike Dunlavey
fonte
9
Isso parece muito o que Chuck Moore (inventor da Forth ) sempre defendeu. Por exemplo, nos Comentários de Chuck Moore sobre a Forth , "eu não acho que seja intrínseco à natureza do software que ele tenha que ser grande, volumoso, com bugs. É da natureza da nossa sociedade. ... Há muito motivação econômica para produzir esse ... bloatware, que eu meio que me sinto irresponsável em levantar e dizer que o imperador não tem roupas ".
Peter Mortensen
3
@PeterMortensen: Concordado. É solitário. Há uma palavra para isso - complexo Cassandra .
precisa saber é o seguinte
2
Embora escrever artefatos de código para "estender" linguagens não seja uma tarefa difícil, é uma boa API que espelha de forma precisa e intuitiva o domínio do problema .
Robert Harvey
3
@ MikeDunlavey: BTW: Você também é o cara "sem perfil" (isso é feito de uma maneira positiva). Alguns meses atrás, usei novamente sua técnica no mundo real para reduzir rapidamente o tempo de carregamento de um arquivo de documento de tipicamente 25 segundos a 1 segundo (um tempo de carregamento que o usuário experimenta diretamente). Foram necessárias algumas iterações e 10 a 20 amostras em todas as iterações foram mais do que suficientes. Os problemas de desempenho estavam obviamente em lugares inesperados.
Peter Mortensen
2
@ Izkata e Peter: Sim, eu sou tão excêntrico. FWIW, eu coloquei alguns vídeos (extremamente amadores), na esperança de facilitar a compreensão. Pausa aleatória. Execução Diferencial. Felicidades.
precisa saber é o seguinte
35

Abstração de alto nível é essencial para alcançar progresso contínuo na computação.

Por quê? Porque os humanos só podem ter tanto conhecimento em suas cabeças a qualquer momento. Hoje, os sistemas modernos e de grande escala só são possíveis porque você pode aproveitar essas abstrações. Sem essas abstrações, os sistemas de software simplesmente entrariam em colapso sob seu próprio peso.

Toda vez que você escreve um método, está criando uma abstração. Você está criando um pouco de funcionalidade oculta por trás de uma chamada de método. Por que você os escreve? Como você pode testar o método, provar que ele funciona e, em seguida, chamar essa funcionalidade a qualquer momento, apenas fazendo a chamada do método, e você não precisa mais pensar no código que está dentro desse método.

Nos primeiros dias da computação, usamos linguagem de máquina. Nós escrevemos programas muito pequenos, bare metal, com conhecimento íntimo do hardware para o qual estávamos escrevendo. Foi um processo meticuloso. Não houve depuradores; seu programa normalmente funcionava ou falhou. Não havia GUI; tudo era linha de comando ou processo em lote. O código que você escreveu funcionaria apenas nessa máquina específica; não funcionaria em uma máquina com um processador ou sistema operacional diferente.

Então, escrevemos linguagens de alto nível para abstrair todos esses detalhes. Criamos máquinas virtuais para que nossos programas possam ser portáveis ​​para outras máquinas. Criamos a coleta de lixo para que os programadores não precisassem ser tão diligentes no gerenciamento de memória, o que eliminou toda uma classe de bugs difíceis. Adicionamos verificação de limites a nossos idiomas para que os hackers não pudessem explorá-los com saturação de buffer. Nós inventamos a Programação Funcional para que pudéssemos raciocinar sobre nossos programas de uma maneira diferente e a redescobrimos recentemente para aproveitar melhor a concorrência.

Toda essa abstração o isola do hardware? Claro que sim. Viver em uma casa em vez de armar uma barraca o isola da natureza? Absolutamente. Mas todo mundo sabe por que vive em uma casa, e não em uma barraca, e construir uma casa é um jogo completamente diferente do que montar uma barraca.

No entanto, você ainda pode montar uma barraca quando for necessário e, na programação, você pode (se quiser) ainda descer para um nível mais próximo do hardware para obter benefícios de desempenho ou memória que talvez você não deseje. caso contrário, obtenha no seu idioma de alto nível.


Você pode abstrair demais? "Ultrapasse o encanamento", como Scotty diria? Claro que você pode. Escrever boas APIs é difícil. Escrever boas APIs que incorporem correta e abrangente o domínio do problema, de maneira intuitiva e detectável, é ainda mais difícil. Empilhar novas camadas de software nem sempre é a melhor solução. Os Padrões de Design de Software , até certo ponto, pioraram essa situação, porque desenvolvedores inexperientes às vezes os procuram quando uma ferramenta mais nítida e mais enxuta é mais apropriada.

Robert Harvey
fonte
11
+1, embora eu ache que você tenha o histórico da programação funcional ao contrário (o cálculo lambda é anterior aos computadores eletrônicos e muitas linguagens funcionais são anteriores à programação simultânea).
amon
11
Eu adicionei um pequeno esclarecimento.
Robert Harvey
2
"Nos primeiros dias da computação, usamos linguagem de máquina. Criamos programas muito pequenos, bare metal, com conhecimento íntimo do hardware para o qual estávamos escrevendo". Às vezes, alguns de nós na programação incorporada ainda o fazem, em microcontroladores de 8-mas que possuem menos de 1K de memória de programa, 64 bytes de RAM e custam cerca de um quarto. Nenhum compilador C lá. (Mas eu costumo trabalhar com microcontroladores de 32 bits com tipicamente 1/2 MB de espaço programa.)
tcrosley
9

Um treinamento realmente bom envolve ambos os extremos, bem como uma ponte entre eles.

No lado de baixo nível: como um computador executa o código desde o início *, incluindo o conhecimento da linguagem assembly e o que um compilador está fazendo.

No lado de alto nível: conceitos gerais, por exemplo, usando matrizes associativas, fechamentos etc. sem perder tempo se preocupando com o modo como funciona sob o capô.

Na IMHO, todos devem ter experiência com os dois, incluindo suas desvantagens, e uma amostra de como passar de conceitos de baixo nível para conceitos de alto nível. Amor matrizes associativas? Ótimo, agora tente usá-los em um processador embarcado de 50 centavos com 1kB de RAM. Como escrever código rápido usando C? Ótimo, agora você tem três semanas para escrever um aplicativo Web; você pode gastar seu tempo lidando com estruturas de dados e gerenciamento de memória usando C, ou você pode gastar seu tempo aprendendo uma nova estrutura da web e implementando o aplicativo da web em alguns dias.

No que diz respeito ao aspecto da complexidade, acho que hoje em dia é muito fácil criar sistemas complexos sem uma compreensão clara do custo de fazê-lo . Como resultado, construímos, como sociedade, uma enorme quantidade de dívida técnica que nos morde de tempos em tempos. É como terremotos (apenas o custo de vida perto de uma falha geológica, certo?), Mas está gradualmente piorando. E eu não sei o que fazer sobre isso. Idealmente, aprenderíamos e melhoraríamos o gerenciamento da complexidade, mas acho que isso não vai acontecer. Um ensino de engenharia responsável precisa incluir muito mais discussões sobre as conseqüências da complexidade do que a maioria das nossas universidades atualmente oferece.


* e, enfim, onde está o "fundamento" de como um computador executa o código? É linguagem assembly? Ou arquitetura de computador? Ou lógica digital? Ou transistores? Ou física de dispositivos?

Jason S
fonte
7

Eu sinto que a programação de alto nível tem muitas vantagens e é uma parte essencial de uma linguagem de programação. Uma das razões pelas quais o Java se tornou bem-sucedido foi o fato de possuir uma biblioteca abrangente. Você consegue mais com menos código - basta chamar uma função predefinida.

Agora podemos distinguir os usuários da linguagem de programação dos gravadores de linguagem de programação (gravadores de compilador). Deixamos as otimizações para os escritores do compilador. Nós nos concentramos mais em manutenção, reutilização, etc.

Todos
fonte
7

O aumento da complexidade dos sistemas é implacável, opressivo e, em última análise, incapacitante. Para mim, como programador de gerações mais antigas, também é amargamente decepcionante.

Venho programando há mais de 40 anos, tendo escrito código em 50 a 100 idiomas ou dialetos diferentes e me tornado especialista em 5 a 10. A razão pela qual posso reivindicar tantos é que, na maioria das vezes, eles são da mesma linguagem, com ajustes. Os ajustes aumentam a complexidade, tornando cada idioma um pouco diferente.

Eu implementei os mesmos algoritmos inúmeras vezes: coleções, conversões, classificação e pesquisa, codificação / decodificação, formato / análise, buffers e strings, aritmética, memória, E / S. Cada nova implementação adiciona complexidade, porque cada uma é um pouco diferente.

Eu me pergunto a mágica criada pelos artistas trapezistas voadores das estruturas da Web e aplicativos móveis, de como eles podem produzir algo tão bonito em tão pouco tempo. Então percebo o quanto eles não sabem, o quanto precisam aprender sobre dados, comunicações, testes ou threads ou o que for antes que o que eles façam se torne útil.

Aprendi meu ofício na era das linguagens de quarta geração, onde acreditamos genuinamente que produziríamos uma sucessão de linguagens de níveis cada vez mais altos para capturar progressivamente cada vez mais partes repetitivas do software de escrita. Então, como isso acabou, exatamente?

A Microsoft e a IBM eliminaram essa idéia retornando ao C para escrever aplicativos para Windows e OS / 2, enquanto o dBase / Foxpro e até o Delphi definhavam. Então a web fez novamente com o seu trio final de linguagens assembly: HTML, CSS e JavaScript / DOM. Foi tudo ladeira abaixo a partir daí. Sempre mais linguagens e mais bibliotecas e mais estruturas e mais complexidade.

Sabemos que deveríamos fazê-lo de maneira diferente. Sabemos sobre CoffeeScript e Dart, sobre Less and Sass, sobre modelo para evitar a necessidade de escrever HTML. Nós sabemos e fazemos de qualquer maneira. Temos nossas estruturas, cheias de abstrações vazadas, e vemos que maravilhas podem ser feitas por alguns poucos escolhidos que aprendem os encantamentos misteriosos, mas nós e nossos programas estamos presos às decisões tomadas no passado. É muito complicado mudar ou recomeçar.

O resultado é que coisas que deveriam ser fáceis não são fáceis, e coisas que deveriam ser possíveis são quase impossíveis, devido à complexidade. Posso estimar o custo de fazer alterações para implementar um novo recurso em uma base de código estabelecida e ter certeza de que estarei certo. Eu posso estimar, mas não posso justificar ou explicar. É muito complicado.

Em resposta à sua pergunta final, aconselho vivamente os programadores mais jovens a começar o mais alto possível sobre o bolo de camadas e mergulhar apenas nas camadas inferiores, conforme a necessidade e o desejo forneçam o ímpeto. Minha preferência é por idiomas sem loops, pouca ou nenhuma ramificação e estado explícito. Lisp e Haskell vêm à mente. Na prática, sempre termino com C # / Java, Ruby, Javascript, Python e SQL porque é onde as comunidades estão.

Palavras finais: a complexidade é o inimigo final! Bata isso e a vida se torna simples.

david.pfx
fonte
Meus 30 anos de programação me ensinaram a usar a linguagem de nível mais alto disponível, que fará o que precisa ser feito e ainda permitirá o uso de linguagens de nível inferior, quando necessário. O ambiente mais fácil para isso é o script de shell, que pode invocar módulos escritos em qualquer idioma. A parte difícil é quebrar a mentalidade dominante de que todas as funcionalidades de um projeto precisam ser implementadas no mesmo idioma.
DocSalvager
@dicsalvage: Eu concordo, e minha grande decepção é a falta de níveis cada vez mais altos. O que o awk poderia fazer em 10 linhas nos anos 80 agora leva 15 linhas em Ruby ou Python, mas procuro algo para fazer isso em 3. E os ambientes bloqueados nos telefones significam que a mesma coisa leva 50 no Java ou no Objetivo C. Não scripts de shell lá!
David.pfx 23/05
O Google "bash para android" mostra muitas pessoas trabalhando em portas. Há também versões do Python como Kivy
DocSalvager
@ DocSalvage: Cedo ou tarde, o ambiente do telefone se unirá à civilização (como a conhecemos). Minha queixa é o tempo necessário para repetir o que parece ter sido concluído. Continuamos tendo que voltar a lançar fundações, alvenaria, drenagem e barracos quando quero construir arranha-céus.
David.pfx
4

Minha pergunta, porém, é como as pessoas se sentem sobre esse "esconderijo" dos elementos de nível inferior. Os programadores mais antigos veem isso como uma dádiva de Deus ou uma camada desnecessária para passar?

Nem mesmo.

A estratificação é necessária porque, sem ela, você chega a um ponto em que seu sistema se torna espaguete insustentável. Esse também é um dos princípios da reutilização: se o desenvolvedor de uma biblioteca fez um bom trabalho, as pessoas que a usam não devem se preocupar com os detalhes da implementação. A quantidade de código enlatado que usamos em nossos sistemas aumentou em ordens de mangitude em relação ao que era quando escrevi meu primeiro programa, 35 anos atrás. Esse crescimento significa que somos capazes de fazer coisas mais poderosas com o passar do tempo. Isso é bom.

O lugar onde isso tem sido um problema para mim é inteiramente cultural. Minha metade pragmática entende que não é mais possível envolver minha mente em todos os detalhes e ser capaz de terminar as coisas que quero que sejam feitas. (Ficar mais velho também não ajuda.) Minha metade do barba grisalha teve dificuldade em deixar passar muitos anos tendo uma compreensão tão refinada de tudo em que trabalhei.

Você acha que os programadores mais jovens se beneficiariam mais com a programação de baixo nível ANTES de explorar os domínios das bibliotecas expansivas?

Como foi apontado em outras respostas, há um equilíbrio a ser alcançado entre atrair e manter a atenção dos neófitos e oferecer a eles uma educação ideal, de baixo para cima. Se você não pode fazer o primeiro, o último não pode acontecer.

Eu vejo coisas em nossa indústria que são paralelas ao resto da sociedade. Costumava ser que quase todo mundo cultivava sua própria comida e passava muito tempo fazendo isso. Desde então, criamos especialistas chamados agricultores que fazem esse trabalho, liberando outros para fazer outras coisas que contribuem para a sociedade. Eu compro minha comida em um supermercado e seria completamente incapaz de produzir a maior parte sozinha, se fosse necessário. Temos uma coisa semelhante acontecendo, embora em uma escala de tempo muito mais compactada. Os programadores são especializados em alguns conjuntos de camadas e não em outros. O cara comum que cria GUIs pode saber que existe espaço de troca, mas provavelmente não sabe nem se importa muito com a maneira como o sistema operacional está gerenciando.

O resultado disso é que não se trata mais apenas de desenvolvimento. A especialização contínua significa que os desenvolvedores precisarão continuar melhorando suas habilidades de comunicação e integração.

Blrfl
fonte
3

Como em tudo, um pouco faz bem, mas dói demais. O problema é que muitos sistemas não sabem quando parar - apenas mais uma abstração, para ajudá-lo a programar mais rapidamente ... mas você acaba codificando no mundo real, onde as coisas nunca são tão simples quanto você deseja, e você gaste mais tempo trabalhando nas bordas do que você gastaria com uma abstração com menos recursos.

É habilmente descrito aqui

ou aqui - "com uma única linha de código, você pode adicionar 500 usuários ao domínio" ...

Suas abstrações tentam esconder a complexidade de você, mas na verdade tudo o que elas fazem é ocultar essa complexidade. A complexidade ainda está lá, é que você tem muito menos controle sobre ela - e é por isso que você acaba com esse tipo de situação.

gbjbaanb
fonte
2

Os programadores mais jovens se beneficiam mais com a aprendizagem de programação de baixo nível ANTES de explorar os domínios das amplas bibliotecas? Se sim, por que?

Acho que não. Ainda existem muitas situações em que é benéfico estar ciente de que a camada abaixo funciona, por exemplo,

  • Ao depurar um problema na camada n, muitas vezes isso pode ser explicado considerando o que acontece na camada n-1(isto é, a camada abaixo). Eu acho que a camada 0 seria "transistores", mas se você quiser explicar um problema com transistores, provavelmente falará sobre física (por exemplo, calor), então talvez a física esteja realmente no nível 0.

  • Ao otimizar o código, infelizmente (às vezes) ajuda a diminuir o nível de abstração, ou seja, implementar um algoritmo em termos de uma camada de nível inferior. No entanto, os compiladores se tornaram muito bons em fazer isso por você, se eles realmente veem todo o código envolvido. Esse motivo se tornou mais popular recentemente com o boom de dispositivos móveis e embarcados, que tendem a ter processadores mais fracos e onde o "desempenho por Watt" é muito mais relevante do que em sistemas de desktop, digamos.

No entanto, em geral, ficou muito mais fácil fazer os computadores fazerem coisas (mesmo que de maneiras ligeiramente ineficientes), o que significa que há muito mais programadores do que costumava ser. Isso, por sua vez, tornou o fator "humano" muito mais importante: a resposta de Robert Harvey já mencionou que "os seres humanos podem ter tanto conhecimento em suas cabeças a qualquer momento", e acho que esse é um aspecto muito relevante hoje em dia.

Uma grande motivação no design da linguagem de programação e da biblioteca (API) é facilitar as coisas no cérebro humano. Até hoje, tudo ainda é compilado no código da máquina. No entanto, isso não é apenas propenso a erros, mas também é notoriamente difícil de entender. Portanto, é muito desejável

  • Peça ao computador para ajudá-lo a encontrar erros lógicos nos programas que você escreve. Coisas como sistemas de tipo estático ou analisadores de código-fonte (ouvi dizer que Eric Lippert trabalha em um relativamente popular hoje em dia) ajudam nisso.

  • Tenha uma linguagem que possa ser processada com eficiência por um compilador e que comunique a intenção do programador a outros programadores para facilitar o trabalho no programa. Como um extremo absurdo, imagine que escrever programas em inglês simples era possível. Outros programadores podem ter um tempo mais fácil para imaginar o que está acontecendo, mas ainda assim, a descrição seria muito difícil de compilar em instrutores de máquinas, e é notoriamente ambígua. Então você precisa de uma linguagem que um compilador possa entender, mas que também seja compreensível.

Dado que muitos compiladores (a maioria?) Ainda são de uso geral, eles apresentam um conjunto de instruções muito genérico. Não há instruções de "apertar um botão" ou "reproduzir este filme". Portanto, descer a hierarquia de abstração faz com que você acabe com programas que são muito difíceis de compreender e manter (embora triviais de compilar). A única alternativa é subir na hierarquia, levando a mais e mais linguagens e bibliotecas abstratas.

Frerich Raabe
fonte
1

"se programadores mais velhos veem inovações como essas como uma dádiva de Deus ou uma camada adicional para abstrair, e por que eles pensam assim?"

Eu tenho programado desde que estava no ensino médio, cerca de 34 anos, começando com o Basic e o Z80 Assembler, passando para C, várias linguagens 4GL, Scheme, SQL e agora várias linguagens da Web. O escopo, a escala e a profundidade dos problemas abordados pela profissão passaram por um período inflacionário ao longo desse tempo, principalmente nos anos 90. Construções como bibliotecas, estruturas e serviços de SO são todos artifícios destinados a lidar com a complexidade que acompanha o espaço expandido de problemas. Eles não são uma dádiva de Deus nem um fardo em si mesmos - apenas uma exploração contínua de um vasto espaço de solução.

Mas, IMHO, "inovação" é melhor entendida em termos de novas formas e não confundida com movimento lateral - reintroduzindo formas que já vimos introduzidas. De certa forma, a fecundidade de um ecossistema sofre quando as formas primitivas não se compõem, quando fixam decisões tomadas no início da evolução ou não conseguem reprocessar seus próprios detritos. Alguns, se não a maioria, das construções nas quais continuamos focados não priorizam o sustento de valor a longo prazo como uma preocupação. Isso começou a mudar - abordagens como Orientação a Serviços e Design Orientado a Domínio, para não mencionar modelos baseados em hipertexto e gráficos, por exemplo, estão alterando o cenário. Como qualquer ecossistema, eventualmente as formas dominantes darão lugar a novas formas; somos melhor servidos ao permitir a diversidade,

"E os programadores mais jovens beneficiam mais o aprendizado de programação de baixo nível ANTES de explorar os domínios das grandes bibliotecas? Se sim, por que?"

Eu argumentaria que a maior parte da linguagem humana se baseia em metáforas há muito esquecidas, portanto, embora eu apoie o aprendizado de programação de baixo nível do ponto de vista da alfabetização científica / numérica, é mais importante que procuremos primitivas que suportem a escala e o escopo de os problemas que estamos enfrentando de uma maneira que podemos ignorar com segurança o nível mais baixo de detalhes. Uma estrutura não é primitiva, nem é um sistema operacional ou uma biblioteca - eles são bastante pobres em fazer o tipo de abstração que realmente precisamos. O progresso real levará as pessoas que (a) sabem o que aconteceu antes e (b) podem pensar de uma maneira nova o suficiente para criar algo diferente o suficiente para explorar um espaço de solução que não foi explorado antes ou que foi explorado e esquecido.

OTOH, mesmo que seu objetivo seja trabalhar como técnico / mecânico, algum nível de exposição de programação de baixo nível ainda será útil para desenvolver suas habilidades de resolução de problemas.

jerseyboy
fonte
1

Meu primeiro programa (quando adolescente de 15 anos) foi em 1974 no PL / 1 em cartões perfurados para um mainframe IBM 370/168. Meu pai estava trabalhando na IBM e tive a sorte de poder ir ao datacenter aos domingos.

Naquela época, um programa de vários milhares de declarações (cartões perfurados) era um programa grande (e pesado também, pois muitos milhares de cartões perfurados pesavam muitos quilos). As interfaces visuais não existiam (um programa típico era lido a partir de sua "entrada padrão" usando um comando de cartão perfurado começando com //GO.SYSIN DD *IIRC, mas eu não dominava a JCL ). O algoritmo era importante, e o IIRC, a biblioteca padrão, era bastante pequena para o padrão atual.

Hoje, programas de vários milhares de linhas são geralmente considerados pequenos. Por exemplo, o compilador GCC possui mais de dez milhões de linhas de código-fonte e ninguém as entende completamente.

Meu sentimento é que a programação hoje é bem diferente da década de 1970, porque você precisa usar muito mais recursos (em particular, bibliotecas e estruturas de software existentes). No entanto, acho que as pessoas que desenvolvem software de datacenter (por exemplo, mecanismos de pesquisa no Google) ou algum software incorporado se preocupam tanto com algoritmos e eficiência quanto o programador médio da década de 1970.

Eu ainda acho que entender a programação de baixo nível é importante ainda hoje (mesmo que a maioria dos programadores não se codifique como algoritmos básicos de contêineres, como árvores balanceadas, matrizes classificadas acessadas dicotomicamente, etc ...) porque entender a imagem toda ainda é importante.

Uma grande diferença entre os anos 1970 e hoje é a relação de custo entre os esforços (humanos) do desenvolvedor e a potência do computador.

Basile Starynkevitch
fonte