Até recentemente, o Dropbox tinha uma estratégia técnica para usar o código C ++ comum para aplicativos móveis iOS e Android. A idéia é clara: escreva o código uma vez em C ++ em vez de duplicá-lo separadamente em Java e Objetivo C. Adotamos essa estratégia em 2013, quando o grupo de engenheiros de desenvolvimento móvel era relativamente pequeno e precisava desenvolver rapidamente o produto. Essa solução permitiu produzir uma grande quantidade de código no Android e no iOS pelas forças de uma pequena equipe.
Agora, abandonamos completamente essa estratégia em favor dos idiomas nativos de cada plataforma (principalmente Swift e Kotlin, que não existiam quando começamos). A solução envolve os (não tão) custos ocultos do compartilhamento de código.
Todos os problemas decorrem do principal: a
sobrecarga acabou sendo mais do que apenas escrever o código duas vezes .
Antes de analisar os vários tipos de sobrecarga, gostaria de esclarecer que nunca chegamos ao ponto em que a maior parte da base de código estava em C ++. Os custos realmente nos impediram de seguir nessa direção.
Também é importante notar que empresas muito maiores, como Google e Facebook, desenvolvem soluções escaláveis de compartilhamento de código há vários anos. Tais soluções não são muito comuns. Embora sistemas de terceiros como o React Native ou o Flutter evitem parte da sobrecarga, alguns custos ainda permanecem (pelo menos até que uma dessas tecnologias se torne popular e madura o suficiente). Por exemplo, o
Airbnb se recusou a usar o React Native por muitos dos mesmos motivos descritos neste artigo.
Todos os custos podem ser agrupados em quatro categorias principais.
Sobrecarga de estruturas e bibliotecas personalizadas
A maneira mais fácil de prever os custos de criação de estruturas e bibliotecas. Eles são divididos aproximadamente em duas subcategorias:
- Estruturas que permitem a interação com o ambiente host para criar um aplicativo móvel completo. Por exemplo:
- Djinni , uma ferramenta para criar declarações entre idiomas de tipos de conexão e interfaces
- Uma estrutura para executar tarefas em segundo plano no thread principal (trivialmente nos idiomas nativos da plataforma)
- Bibliotecas para substituir os padrões de idioma ou soluções de código aberto que podem ser usadas em idiomas nativos, por exemplo:
- json11 para (des) serializar JSON
- nn ponteiros não nulos para C ++
Nada disso é necessário se você permanecer nos idiomas nativos da plataforma. E nossa participação em projetos de código aberto em idiomas nativos provavelmente seria mais benéfica para os desenvolvedores. Na comunidade C ++, a cultura de código-fonte aberto não era (e é?) Tão desenvolvida quanto na comunidade de desenvolvedores móveis, tanto mais que a comunidade
móvel C ++ praticamente não existe.
Observe que esses custos são especialmente altos para C ++ (ao contrário de outras possíveis linguagens não nativas, como Python ou C #), porque não há uma biblioteca padrão totalmente funcional. No entanto, apenas o C / C ++ possui um compilador suportado pelo Google e pela Apple, portanto, mudar para outro idioma causa vários outros problemas.
Ambiente de desenvolvimento customizado de grandes dimensões
Existem muitas ferramentas no ecossistema móvel para melhorar a eficiência do desenvolvimento. Os IDEs móveis são muito funcionais e o Google e a Apple investiram muitos recursos para torná-los ideais em suas plataformas. Afastando-nos dos padrões, abrimos mão de algumas vantagens. Primeiro de tudo, a depuração de idioma nativo geralmente supera a depuração de C ++ no IDE por padrão.
Lembro-me especialmente de um erro que causou um bloqueio na estrutura de streaming em segundo plano, o que levou a falhas acidentais de aplicativos. Esses erros são difíceis de rastrear, mesmo com uma pilha simples e padrão. Como o problema envolvia a depuração de código multiencadeado em execução entre C ++ e Java, demorou semanas para rastrear!
Além de perder as ferramentas padrão, tive que investir tempo na criação de minhas próprias ferramentas para oferecer suporte ao código C ++ comum. Mais importante ainda, era necessário um sistema de compilação personalizado para criar bibliotecas que continham código C ++, bem como shells Java e Objective-C. Ele deve gerar metas que o Xcodebuild e o Gradle entendam. A criação de um sistema desses nos levou muitos recursos, porque ele precisava ser constantemente atualizado para dar suporte às mudanças nos dois sistemas de compilação.
Substituição de plataforma para diferenças de plataforma
Embora o iOS e o Android sejam "aplicativos móveis" que geralmente oferecem os mesmos recursos, existem algumas diferenças nas próprias plataformas que afetam a implementação. Por exemplo, como um aplicativo executa tarefas em segundo plano. Mesmo coisas semelhantes podem começar a diferir bastante ao longo do tempo (por exemplo, interagindo com a câmera).
Como resultado, você não pode simplesmente escrever código uma vez e executá-lo em outra plataforma. Você precisa gastar muito tempo integrando e codificando para uma plataforma específica e, às vezes, esse código termina no nível C ++!
Economias teóricas ao escrever código apenas uma vez não correspondem à realidade, o que reduz imediatamente a eficácia dessa abordagem.Despesas gerais para contratação, treinamento e retenção de desenvolvedores
Por último, mas não menos importante, é o custo de treinamento e / ou contratação de desenvolvedores para trabalhar com nossa pilha muito peculiar. Quando o Dropbox começou a usar essa estratégia para dispositivos móveis, tínhamos um grupo principal de desenvolvedores experientes em C ++. Este grupo lançou o projeto C ++ e treinou outros desenvolvedores móveis.
Com o tempo, esses desenvolvedores foram para outras equipes e outras empresas. O restante não possuía experiência suficiente para preencher a lacuna na liderança técnica e tornou-se cada vez mais difícil encontrar engenheiros experientes com experiência relevante em C ++ interessados em desenvolver dispositivos móveis.
Como resultado, fomos confrontados com uma falta real de conhecimento crítico para manter a base de código C ++. Restavam apenas duas opções, e cada uma exigia esforços significativos:
- Encontre e contrate candidatos com um conjunto de habilidades muito específico (tentamos sem sucesso por um ano).
- Treine seus próprios desenvolvedores de dispositivos móveis (ou C ++), o que é quase impossível de fazer na ausência de idosos com o conjunto certo de habilidades para concluir o treinamento. Mesmo quando o grupo principal ainda não havia se dispersado, os desenvolvedores móveis geralmente não estavam interessados em C ++, portanto, encontrar pessoas para aprender também era um grande problema.
Além da contratação, o lançamento de sua própria pilha de tecnologia criou um problema de retenção - os desenvolvedores móveis simplesmente não queriam trabalhar em um projeto C ++. Isso fez com que muitos engenheiros talentosos deixassem o projeto, em vez de continuar sofrendo com uma pilha personalizada mal mantida. Em geral, a comunidade de desenvolvedores de dispositivos móveis é muito dinâmica - novas tecnologias e modelos aparecem com frequência e estão sendo implementados rapidamente. Os melhores engenheiros adoram manter suas habilidades atualizadas.
Um produto maduro com uma pilha padrão não é fácil de manter atualizado. Você sacrifica a novidade pela estabilidade. Esse problema aumenta significativamente se você se trancar em uma pilha personalizada fora do ecossistema móvel mais amplo.
Conclusão
Uma vez, escrever um código uma vez para diferentes plataformas parecia bastante, mas os custos associados a ele superavam suas vantagens (que, em qualquer caso, eram menos do que o esperado). No final, não usamos mais uma base de código comum por meio do C ++ (ou qualquer outra maneira não padrão), mas escrevemos código em nossos idiomas nativos para cada plataforma.
Além disso, queremos que nossos engenheiros se sintam bem e possam contribuir com a comunidade. Por isso, decidimos alinhar nossa prática com os padrões da indústria.