Aviso Longrid: Você foi avisado, muitas cartas.
Há muito tempo desenvolve um formato de distribuição para aplicativos "livres" de dependências em todo o sistema. O Ubuntu é muito, muito ativo na promoção de seu snap, gnome - flatpack. Ambos prometem o paraíso e liberdade de rpm / deb. Vamos pensar no problema que eles querem resolver e no preço que eles pedem a solução para esse problema.
Bibliotecas
Ninguém no mundo moderno pode escrever um aplicativo sem usar o código de outra pessoa. Existem várias razões:
- Muitas bibliotecas são tão sérias que escrever sua funcionalidade do zero é uma tarefa assustadora. Exemplos - suporte para unicode, renderização de fontes, matemática.
- Outras bibliotecas oferecem um conjunto bastante modesto de funções, mas são escritas tão bem que escrever pelo menos tão bem é quase impossível. Bibliotecas padrão de linguagens de programação, várias implementações da libc, etc.
- O custo de trabalhar com o código de outra pessoa (ao qual esta seção é dedicada) geralmente é menor do que o custo de manutenção do seu código. É provável que a densidade de "bugs por linha de código" seja comparável, e você deve capturar seus próprios bugs. Bibliotecas estrangeiras (populares) provavelmente serão depuradas e corrigidas pelas mãos erradas.
A chave é que, mesmo se pudermos escrever a funcionalidade de uma única biblioteca a partir do princípio, o número total de funções (e dependências) proporcionará um aumento quase exponencial no número de tarefas que precisam ser resolvidas, adiando o horário de início do trabalho no código do próprio programa. na distância inatingível.
Um exemplo para perceber a escala do drama: digamos que seu aplicativo use duas linhas de entrada como argumentos opcionais e as exiba juntas após a normalização. Se você estiver escrevendo um aplicativo industrial (um aplicativo que se parece com um "real"), então:
- Você precisa de um analisador de linha de comando
- O que deve aceitar unicode
- E talvez dê ao usuário uma dica de que ele selou o nome do argumento
- O que requer comparação fonética
- E talvez expressões regulares
- Em geral, você precisará dar suporte não apenas ao Unicode, mas também a outras localidades, o que requer uma biblioteca de suporte à localidade e TODAS as pessoas criadas no contexto das localidades.
- A concatenação de strings com normalização é outro uso de uma biblioteca Unicode separada; você mesmo não o implementa.
- A exibição na tela (ajuda da linha de comando, seu resultado) provavelmente requer suporte para ncurses, uma biblioteca que suporta terminais diferentes (você pode usar o modo de texto, mas os aplicativos costumam usar recursos de cores).
- Os testes envolvem o uso de uma estrutura de teste, possivelmente uma biblioteca para moks.
É claro que essa complexidade para a tarefa de "duas linhas" é uma superengenharia grosseira, mas assim que você começa a fazer algo mais, a idéia de "tudo sozinho" começa a ir além dos limites do observável e realizado.
Quantas bibliotecas você acha que são necessárias para garantir que o http (s) de ondulação: // ... funcione? Muito. Você usará um, mas as dependências de suas dependências são suas dependências.
Copypaste e vending VS link dinâmico
Embora o uso de bibliotecas seja inevitável, o uso em si pode variar na implementação. Observe que temos duas palavras importantes: "uso" e "implementação de uso". O que significa use? Na sua forma mais rude - a capacidade de chamar o código da biblioteca quando necessário. E aqui estão as implementações disso:
- Podemos copiar o código que executa as operações que precisamos. Na forma de um pedaço de código (copiar e colar), como um módulo separado em uma linguagem de programação (arquivo de objeto para linguagens compiladas) ou como um módulo separado (para linguagens interpretadas). Em algum lugar ao lado dele está "copie o arquivo de origem da biblioteca para o seu diretório com o aplicativo". Que problemas isso cria? O principal, principal problema é que perdemos (para sempre) a conexão com o original. Mesmo que o autor da biblioteca original corrija o erro, não o saberemos. Além disso, se apenas copiarmos o código, a próxima pessoa que trabalha no programa nem será capaz de descobrir que esse código é "estranho". De fato, seguimos o caminho da pergunta "escrever do zero" e pegamos o de outra pessoa. No entanto, cortamos apenas um pedaço, porque se houver erros neste código (mas eles não estarão lá , eles estão lá ), sua correção exigirá que o corretor siga em frente e entenda a essência do problema até o fim. Mesmo que o teste exija a leitura de centenas de milhares de linhas de código fonte e centenas de RFCs (além de comentários de que as implementações são diferentes das RFCs), não temos outra maneira. O principal erro neste local é que perdemos informações de que esse código é estranho. Ter comentários no arquivo pode ajudar, mas exigirá um envolvimento ativo e profundo da pessoa, porque se escrevermos no comentário "extraído da libfoobar, src / lib / foo.c versão 364a51577f3782dbf8e5d2482ab941980357c492", alguém precisará ver onde a libfoobar está localizada, qual é a versão e o que mudou em relação à versão anterior. "Para simplificar esse processo, precisamos de meta-informações legíveis por máquina.
- Se acompanharmos o "código de outra pessoa" com meta-informações e usarmos programas para gerenciar esse código (em vez de copiar e colar), isso será chamado de venda , ou seja, inclusão controlada do código de outra pessoa no seu código. Tecnicamente, a venda pode ocorrer no estágio do texto de origem, vinculando objetos a um arquivo executável, importando módulos (em intérpretes) do aplicativo ou até vinculando dinamicamente à versão "sua" da biblioteca (mais sobre isso mais adiante).
- Por fim, podemos executar links dinâmicos no estágio de lançamento do aplicativo. Para linguagens compiladas, esses são exemplos comuns; para linguagens interpretadas, há um módulo na importação em todo o sistema. Se vários aplicativos puderem importá-lo, essa é uma biblioteca compartilhada. Se o aplicativo "trouxe seu módulo", a biblioteca é "própria", mesmo que sua interface implique uma "biblioteca compartilhada". Por exemplo, se um aplicativo usa sua versão "própria", independentemente de ser diferente da versão geral ou não, então isso é venda automática. E se o sistema for importado, essa é uma biblioteca compartilhada.
Qual é a diferença entre esses métodos? Apresentarei brevemente argumentos, que foram discutidos várias vezes em muitos artigos. Cada um desses argumentos permanece válido, apesar da presença de contra-argumentos vizinhos:
- Economizando memória (RAM e disco) por isso, reduzindo o tamanho do sistema instalado. Quanto mais aplicativos usarem o mesmo, maior será a economia de memória. Assim, pelo contrário, quanto mais "suas" bibliotecas um aplicativo oferecer, mais "gorda" será.
- O debate sobre quem monitora as vulnerabilidades é o sistema (fornecendo atualizações da biblioteca) ou o autor do aplicativo (atualizando-o a tempo).
- Resolução de conflitos de dependências (a venda resolve esse problema, uma vez que as bibliotecas compartilhadas exigem atenção e precisão de todos os participantes do processo, às vezes criando dificuldades intransponíveis), o mesmo lendário inferno da dll.
- Novas versões de bibliotecas - elas aparecem a pedido dos autores do aplicativo ou por decisão dos autores da distribuição. Em um caso, o autor pode trazer o novo recurso de que precisa; em outro, a distribuição pode melhorar o aplicativo existente, suportando algo novo na biblioteca (por exemplo, as telas hidpi começaram a funcionar corretamente em todos os aplicativos dinamicamente vinculados às bibliotecas qt / gtk) .
Todas essas questões foram tratadas várias vezes antes. Em vez disso, quero focar nos aspectos sociais da bacia hidrográfica "toda minha" e "toda comum".
Contrato social e mantenedores de poder
Bibliotecas compartilhadas são cooperação, poder e responsabilidade. As pessoas que determinam quais bibliotecas compartilhadas estão disponíveis no sistema operacional determinam aos fabricantes de software quais bibliotecas compartilhadas podem usar. Muitos softwares podem usar bibliotecas diferentes, e a indicação de qual versão exata usar é deixada ao critério do vinculador (para idiomas compilados) ou do manipulador de arquivos de dependência (pip, bundler, etc.). Se todos os aplicativos na distribuição forem construídos com os mesmos requisitos, a graça será: se houver um erro em alguma biblioteca, o mantenedor dessa biblioteca atualizará a versão e a correção será aplicada automaticamente a todos os aplicativos. Mesmo se o aplicativo for lançado a cada dois anos, a correção no openssl condicional será aplicada dentro de uma semana. Se em um SO específico tiver sido tomada uma decisão de abandonar o protocolo antigo, algumas modificações (por exemplo, a interface do usuário), essas alterações também serão aplicadas a todos. Aparência em um estilo geral que (talvez) possa ser alterado pelo usuário de uma vez por todas. Isso não é graça?
Poder e a luta por ele
... Essa graça exige que todos os aplicativos possam trabalhar com a versão selecionada da biblioteca. Mas e se algum aplicativo quiser uma função muito, muito nova da biblioteca e todos os outros aplicativos não quiserem usá-la, porque esta, por exemplo, não é uma versão LTS da biblioteca, ou seja, não é estável o suficiente? Mas o kit de distribuição pode se recusar a mudar para novas versões "por princípio", porque prometemos aos usuários apenas correções de bugs e novas versões somente na próxima versão do sistema operacional, que (como) será lançada em meio ano. E isso causa resistência por parte dos autores do aplicativo. Quem é você para me dizer com quais versões devo trabalhar? Eu sou um autor, vejo assim. Preciso do libfoobar 3.14-pre2 ou mais antigo, não do seu antigo e insípido libfoobar 3.10.
... Neste ponto, o autor simplesmente escreve nos requisitos do aplicativo libfoobar>=3.14-pre2
. O mantenedor pega e corrige a solicitação, além de excluir o código que dependia dessa biblioteca. Talvez. Ou simplesmente se recusa a aceitar uma nova versão com essa dependência até que essa dependência (libfoobar 3.16) esteja na nova versão da distribuição.
Se o autor realmente precisar que os usuários usem a nova versão (por exemplo, porque o autor não deseja oferecer suporte à versão antiga), ele procurará soluções alternativas para enviar o aplicativo ao usuário.
O mesmo acontece quando existem várias distribuições, algumas mais novas, outras mais antigas. Mantendo distribuições antigas, é difícil testar com diferentes bibliotecas. Portanto, a opção "enviar com suas bibliotecas" aparece quase imediatamente.
Tragédia comunitária
Isso cria os pré-requisitos para o surgimento de uma tragédia da comunidade:
- Cada fabricante (autor do software) deseja enviar conforme necessário. Adaptar-se às regras de outras pessoas (versões) é uma perda de tempo e esforço, tanto mais que existem muitas distribuições diferentes no mundo
- Os usuários querem novas versões.
Ao mesmo tempo, quanto mais aplicativos acompanham suas bibliotecas, menor é o uso de bibliotecas do sistema. Lembra da Grace? Quanto menos "universal", menor a graça. Se uma biblioteca compartilhada for usada por 5 aplicativos diferentes de 995, o benefício dessa biblioteca será de 0,5%. É uma pena, sim. Além disso, isso prejudica todos os usuários, mesmo aqueles que, em princípio, não têm uma necessidade aguda de um novo recurso - mas se o aplicativo estiver disponível apenas no formulário de venda automática, o usuário não terá opções.
Acontece que temos um extremo global: todos os aplicativos usam apenas bibliotecas compartilhadas (graça comum máxima, inconveniência para os autores de aplicativos individuais) ou "cada um por si" (distribuição espessa, com vários aplicativos que podem ter vulnerabilidades não detectadas, mas amplamente usadas, comer muita memória, mas o autor de cada aplicativo é conveniente).
É aqui que chegamos à disputa rpm / deb VS snap / flatpack
Liberdade ou escravidão?
O Ubuntu defende muito, muito fortemente o snap'y. O GNOME está confiante de que o futuro está nos planos. Cada um deles é uma estrutura para aplicações profundamente individualistas. Todos os tipos de elétrons, que possuem não apenas o capô do compartimento do motor, mas também o sistema operacional do compartimento do motor. Própria libc, própria libssl, própria regexp, próprias ncurses, etc. Somente o núcleo age como comum, ou seja, de fato, esse é o mesmo aplicativo em contêiner, mas para a área de trabalho. Dê a cada um o seu próprio núcleo e você obterá o appliance na forma de uma máquina virtual. Adicione os metadados - e você obtém um contêiner do Docker.
O individualismo das aplicações (autores das aplicações) é compreensível, mas quem representa o bem comum? Uma grande melhoria local é compensada por uma leve degradação geral da distribuição multiplicada por aplicações puramente. Se todos fizerem melhorias locais para si mesmos, a quantidade de redução ao valor recuperável se tornará maior que o benefício da quantidade de melhoria.
Parece que, nesse local, os criadores de distribuições devem agir como guardiões de interesse comum. No entanto ...
Política
O Ubuntu depende do Debian muito mais do que a Canonical (a empresa Ubuntu) gostaria. O valor do Ubuntu não está nos esforços dos mantenedores do Ubuntu, mas em um enorme repositório de software vindo do Debian de uma forma em que todos os aplicativos funcionam bem juntos através dos esforços de milhares de mantenedores dos pacotes individuais que possuem a distribuição Debian. A Canonical acrescenta ainda mais seus esforços para aprimorar o resultado - e por isso é amada por alguns. Adicione um pouco de marketing e um ciclo de vida fixo, que é do agrado da empresa, e obteremos um ótimo produto.
... O que depende da vontade de milhares de voluntários em algum lugar por aí.
O que não combina com quase nenhuma empresa comercial. Como quebrar esse vício? É isso mesmo, criando seu próprio pacote de aplicativos. Quanto mais aplicativos houver, menos vantagens no upstream prejudicarão a empresa. Basta lembrar a história quando uma votação no Debian no systemd enterrou o iniciante, desenvolvido pela Canonical.
Mas mantenha várias dezenas de milhares de aplicativos, alguns dos quais são de seu próprio espaço (erlang, go, perl, python, R, julia etc.), e alguns são monstros na área de assunto correspondente (navegadores, emacs, tex, pacemaker etc.) - esses são trabalho pesado. Não é de admirar que sejam milhares de mantenedores.
... E há uma ideia. E, deixe, os próprios autores de aplicativos Manter aplicativos. Vamos dar a todos uma caixa de areia, eles devem cavar. Os autores obtêm liberdade, Canonical - aplicativos que não são dependentes do Debian e que pelo menos alguém mantém de graça. Os usuários recebem ...
... aplicativos que são gordos, pesados, cujas atualizações são irregulares e que podem facilmente manter as vulnerabilidades sem correção por anos ... Mas algumas delas são novas e brilhantes.
Então, o que vem a seguir?
Imagine um mundo em que todos carreguem tudo com eles ... Você sabe como é? Dê uma olhada no chefsdk. Ele é enviado dentro de seu postgresql (com suas dependências), seu rabbitmq (que depende de seu erlang), e o chef-server também está em erlang, então ele também tem seu próprio erlang. De repente, temos dois erlangs e dezenas de cópias das mesmas bibliotecas dentro do mesmo aplicativo, ligeiramente diferentes na versão. Esta não é a opção final, pois por dentro, ainda existem bibliotecas comuns entre os componentes. Se as aprofundarmos, obteremos várias dezenas de cópias do openssl e libc para um aplicativo. Nem mesmo em sua forma final, parece 600MB por aplicativo.
... Que, é claro, é um múltiplo da aplicação eletrônica média ... E 12 vezes maior que todo o servidor mariadb (todo o DBMS!), Ou krita ou gimp (grandes aplicações gráficas).
E se todo mundo vai ser assim? Eu tenho 2000 pacotes instalados no meu computador (sem contar -dev e lib) ... 2000 * 300 = 600GB (Para o tamanho médio do resultado, tirei metade do chefsdk, porque nem todo mundo é tão terrível com as dependências). Agora eles ocupam cerca de 7 GB (incluindo recursos, como documentação, editores de textura, modelos de CAD etc.).
Se isso se transformar em 600 GB, não é uma pura tragédia de comunidades? A cada momento, observamos a otimização local (e a solução do inconveniente de outra pessoa), mas, juntos, a soma dessas otimizações locais reduz a otimização geral do sistema. Na minha opinião, mais do que o ganho local de cada um dos participantes.
Entendo por que os empurrões Canonical se encaixam. Eu entendo isso e não aprovo.