Desenvolvimento da biblioteca: da API ao lançamento público

Vejamos as bibliotecas não do lado mais familiar para nós, ou seja, do usuário, mas do ponto de vista do desenvolvedor da biblioteca de desenvolvimento móvel. Vamos falar sobre quais abordagens devem ser seguidas ao desenvolver sua biblioteca. Começamos, é claro, projetando uma API que você gostaria de usar, o que seria conveniente. Pensaremos no que precisa ser considerado para criar não apenas código funcional, mas uma biblioteca muito boa e chegar ao ponto de lançar um lançamento público adulto real. Asya Sviridenko nos ajudará nisso, que compartilhará sua experiência considerável no desenvolvimento da biblioteca móvel SpeechKit em Yandex .

O material será útil não apenas para os envolvidos no desenvolvimento de uma biblioteca ou estrutura, mas também para aqueles que desejam separar uma parte de seu aplicativo em um módulo separado e depois reutilizá-lo ou, por exemplo, compartilhar seu código com o resto da comunidade de desenvolvedores, publicando-o em acesso público.

Para todos os outros, a história será repleta de histórias genuínas da vida da equipe móvel do SpeechKit, por isso deve ser divertido.


Conteúdo


  • Minuto SpeechKit .
  • Projetando uma API conveniente e compreensível que você deseja usar.
  • Desenvolvimento . O que adicionar ao código para que ele não apenas funcione e execute a funcionalidade, mas também ajude seus usuários.
  • Lançamento - o que você não deve esquecer quando lança o lançamento.


SpeechKit minute


Não vou perguntar se você ouviu falar sobre o SpeechKit, porque mesmo no Yandex, nem todo mundo sabe o que é.

O SpeechKit é a porta para todas as tecnologias de fala Yandex . Usando esta biblioteca, você pode integrar tecnologias de fala em seu aplicativo: reconhecimento e síntese de voz, ativação por voz.

Você provavelmente já ouviu falar sobre a assistente de voz Alice - ela apenas trabalha com base no SpeechKit. O SpeechKit em si não inclui reconhecimento ou síntese, acontece no servidor. Mas é através da nossa biblioteca que tudo pode ser integrado ao aplicativo.

A seguir, geralmente vem a pergunta - se tudo no servidor acontece, o que a biblioteca faz? Por que é necessário?

A biblioteca faz muito:

  1. Sincronização de todos os processos. Por exemplo, usando um assistente de voz, o usuário clica em um botão, diz alguma coisa, interrompe o assistente, faz solicitações - tudo passa pela biblioteca. Para o usuário da nossa biblioteca isso é transparente, eles não devem se preocupar com tudo isso.
  2. Trabalho em rede Como tudo acontece no servidor, você precisa obter dados de lá, processá-los e entregá-los ao usuário. O SpeechKit agora pode acessar vários servidores diferentes na mesma conexão de rede: um está envolvido no reconhecimento, o outro está na alocação de significado, o terceiro está no reconhecimento da música, etc. Tudo isso está oculto na biblioteca, os usuários não precisam se preocupar com isso.
  3. Trabalhe com fontes de áudio. Estamos lidando com a fala humana e o trabalho com áudio também ocorre no SpeechKit. Além disso, não podemos apenas escrever de um dispositivo padrão, mas também receber dados de qualquer lugar. Pode ser um arquivo ou um fluxo - podemos trabalhar com tudo isso.

O SpeechKit é usado em equipes internas. Agora ele foi integrado por 16 equipes Yandex. E sabemos até sobre várias equipes externas que fizeram isso também.

Desenho


Vamos pensar no que queremos dizer com uma aplicação conveniente. Geralmente, este é um UX atencioso e compreensível, a solução para nossos problemas, operação estável etc.

Quando dizemos que uma biblioteca é conveniente, primeiro queremos dizer que ela possui uma API que é fácil de usar. Como conseguir isso?

Princípios básicos


Esses são alguns dos aspectos que aprendi com minha experiência com o SpeechKit.

  • Antes de tudo, lembre-se de que seus usuários são desenvolvedores .

Por um lado, isso é bom, porque você não pode explicar aos usuários comuns: "Veja, o back-end está conosco e, portanto, nada funciona, e estamos bem!" Você pode explicar aos desenvolvedores - você pode explicar muito aos desenvolvedores!

Por outro lado, você obtém esses usuários que definitivamente aproveitarão a oportunidade para encontrar um buraco e quebrar algo se você o deixar. Todos nós usamos bibliotecas e tentamos tirar o máximo proveito delas. Eles alegam que estão fazendo apenas isso, isso e isso, e estamos pensando: "Não, agora vamos fazer uma brincadeira aqui, vamos repassar e tudo será como deveria".

Além disso, o fato de os usuários serem desenvolvedores significa que você sempre terá uma montanha de dicas e truques sobre como desenvolver e como melhorar tudo.

O segundo ponto importante é totalmente consistente com o primeiro.

  • Tudo o que não é permitido na sua biblioteca deve ser proibido,
    para que não haja brechas indesejadas.

Se seus usuários começarem a fazer algo com a biblioteca que você não esperava, esse é um caminho direto para erros e para aqueles que são difíceis de depurar. Tente usar tudo o que o idioma fornece e a tecnologia que você usa: público / privado, final, reprovado, somente leitura. Reduza o escopo, proíba a herança e o uso de alguns métodos, marque propriedades que não podem ser alteradas - forneça tudo o que for possível para impedir algo que sua biblioteca simplesmente não foi projetada para fazer.

  • Não permita ambiguidades na interpretação da API da sua biblioteca.

Se essa classe específica puder ser criada de uma maneira, negue todas as outras. Se essa propriedade não puder ser nula, especifique-a explicitamente. No iOS, há inicializador nulo / não nulo, designado, o mesmo ocorre em Java e Android. Use tudo isso para que o usuário abra o arquivo, abra sua classe, repasse-o e entenda imediatamente o que pode ser feito e o que não pode ser feito.

API do SpeechKit do caso


Usando o SpeechKit como exemplo, mostrarei como refatoramos a versão 2 para a versão 3. Alteramos muito a API e tentamos usar todos esses princípios.

A necessidade surgiu porque a API era complexa e "teórica" . Havia componentes globais nele que precisavam ser chamados primeiro - não chamados - tudo não funcionou. Configurações muito estranhas foram definidas. A API era bastante "teórica", porque o SpeechKit fazia parte do Navegador e, em seguida, essa peça foi levada para a biblioteca. A API trabalhou essencialmente com os casos usados ​​no Navigator.

Gradualmente, o número de usuários aumentou e começamos a entender o que eles realmente precisavam: quais métodos, retornos de chamada, parâmetros. Eles vieram até nós com solicitações que a API não permitia implementar. Isso foi repetido várias vezes e ficou claro que a API não estava à altura. Então nos envolvemos na refatoração.

O processo de refatoração foi longo (meio ano) e doloroso (todo mundo estava infeliz) . A principal dificuldade não era pegar uma montanha de código e reescrevê-la. Era impossível simplesmente refatorar, mas era necessário suportar todas as versões ativas que estavam em uso. Não podíamos dizer apenas aos nossos usuários: "Gente, sim, isso não funciona para você, sim, você precisa desse recurso - faremos tudo na versão 3, aguarde seis meses!"

Como resultado, a refatoração levou muito tempo, e o processo foi doloroso, e também para os usuários. Porque, no final, alteramos a API sem compatibilidade com versões anteriores. Eles vieram até eles e disseram: “Aqui está um novo e bonito SpeechKit, por favor, pegue!” - eles responderam: "Não, não temos planos de atualizar para a sua versão 3.0." Por exemplo, tivemos uma equipe que mudou para esta versão em um ano. Portanto, durante um ano inteiro, apoiamos a versão anterior para eles.

Mas o resultado valeu a pena. Temos integração simples e menos bugs . Isso é o que eu mencionei nos princípios básicos de design da API. Se você tem certeza de que sua API está sendo usada corretamente, definitivamente não há problemas nesta parte: todas as classes são chamadas corretamente, todos os parâmetros estão corretos. Encontrar bugs é muito mais fácil, menos casos em que algo pode dar errado.

Abaixo está um exemplo de como era a classe principal que lida com o reconhecimento antes da refatoração.

// SpeechKit v2 @interface YSKRecognizer: NSObject @property (nonatomic, strong, readonly, getter=getModel) NSString* model; @property (nonatomic, assign, getter=isVADEnabled) BOOL VADEnabled; - (instancetype)initWithLanguage:(NSString *)language model:(NSString *)m; - (void)start; - (void)cancel; - (void)cancelSync; @end @interface YSKInitializer: NSObject - (instancetype)init; - (void)dealloc; - (void)start; + (BOOL)isInitializationCompleted; @end extern NSString *const YSKInactiveTimeout; extern NSString *const YSKVADEnabled; @interface YSKSpeechKit: NSObject + (instancetype)sharedInstance; – (void)setParameter:(NSString *)name withValue:(NSString *)value; @end 

Esta é uma classe regular que herda de NSObject. Vamos considerar cada um de seus detalhes separadamente. É claro que podemos herdar dele, redefinir alguns métodos nele - tudo o que pode ser feito com o NSObject.

Em seguida, ao criar, duas linhas (linguagem e modelo) são passadas para ele. Quais são essas linhas? Se você passar no idioma "Olá, mundo", a saída será uma tradução, ou o quê? Não é muito claro.

Além disso, como esse é o sucessor do NSObject, podemos chamar init, new, etc. O que vai acontecer? Funcionará ou esperará alguns parâmetros?

É claro que conheço as respostas para essas perguntas, conheço esse código. Mas as pessoas que estão vendo isso pela primeira vez não entendem por que isso é tudo. Mesmo os métodos com setter e getter não parecem nada com o que pode parecer no iOS. Os métodos start, cancel, cancelSync (e o que acabou de cancelar - é aSync?) - o que acontecerá se forem chamados juntos? Muitas perguntas para esse código.

Em seguida, vem o objeto sobre o qual falei (YSKInitializer), que deve ser iniciado para que tudo funcione - geralmente é algum tipo de mágica. Pode-se ver que esse código foi escrito por desenvolvedores que não escrevem para iOS, mas estão envolvidos em C ++.

Além disso, as configurações desse reconhecedor foram definidas por meio de componentes globais que foram transferidos para outro objeto global e, de fato, era impossível criar dois reconhecedores diferentes com diferentes conjuntos de parâmetros. E esse foi provavelmente um dos casos mais populares que não suportavam a API.

Do que v3 é melhor que v2


O que obtivemos quando refatoramos e mudamos para a versão 3?

  • API completamente nativa.

Agora, nossa API do iOS parecia a API do iOS, a API do Android parecia o Android.

Um ponto importante que não percebemos imediatamente é que as diretrizes da plataforma são muito mais importantes que a uniformidade da API da sua biblioteca.

Por exemplo, as classes para Android são criadas usando construtores, porque esse é um padrão muito compreensível para desenvolvedores de Android. No iOS, isso não é tão popular, por isso é usada uma abordagem diferente: criamos objetos com uma classe especial de configurações.

Lembro-me de como discutimos por um longo tempo sobre esse assunto. Pareceu-nos importante que o desenvolvedor adotasse nosso código no iOS ou Android, e a correspondência seria de 99%. Mas isso não é verdade. Melhor, o código será semelhante à plataforma para a qual está sendo desenvolvido.

  • Inicialização simples e intuitiva .

Este objeto é necessário - aqui estão suas configurações, crie-as, transfira-as - lucre! Ou seja, não há configurações globais ocultas que precisam ser transferidas para algum lugar.

  • Falta de componentes globais.

Jogamos fora componentes globais que confundiram, assustaram e causaram muitas perguntas, mesmo entre os desenvolvedores desta biblioteca, não apenas os usuários.

Agora, a mesma classe na nova versão se parece com esta (ainda é Objective-C - você não podia mudar para Swift então).

 // SpeechKit v3 NS_ASSUME_NONNULL_BEGIN __attribute__((objc_subclassing_restricted)) @interface YSKOnlineRecognizer: NSObject<YSKRecognizing> @property (nonatomic, copy, readonly) YSKOnlineRecognizerSettings *settings; - (instancetype)initWithSettings:(YSKOnlineRecognizerSettings *)s audioSource:(id<YSKAudioSource>)as NS_DESIGNATED_INITIALIZER; + (instancetype)new __attribute__((unavailable("Use designated initializer."))); - (instancetype)init __attribute__((unavailable("Use designated initializer."))); @end NS_ASSUME_NONNULL_END @protocol YSKRecognizing <NSObject> - (void)prepare; - (void)startRecording; - (void)cancel; @end @interface YSKOnlineRecognizerSettings: NSObject<NSCopying> @property (nonatomic, copy, readonly) YSKLanguage *language; @property (nonatomic, copy, readonly) YSKOnlineModel *model; @property (nonatomic, assign) BOOL enableVAD; - (instancetype)initWithLanguage:(YSKLanguage *)l model:(YSKOnlineModel *)m NS_DESIGNATED_INITIALIZER; @end @interface YSKLanguage: YSKSetting + (instancetype)russian; + (instancetype)english; @end 

Este é o sucessor do NSObject, mas agora estamos falando claramente do fato de que você não pode herdar dele. Todos os métodos que são característicos deste objeto são transferidos para um protocolo especial. É criado usando as configurações e o audioSource. Agora todas as configurações são encapsuladas em um único objeto, que é transferido especificamente aqui para definir as configurações de um reconhecedor específico.

Além disso, removemos o trabalho com áudio daqui, ou seja, o reconnaiser agora não é o componente que grava o áudio. Este componente lida com problemas de reconhecimento e qualquer fonte pode ser transferida aqui.

Outros métodos de criação através do novo ou do init são proibidos, porque essa classe precisa de configurações padrão. Por favor, se você quiser usá-lo, crie pelo menos algumas configurações padrão.

O principal é que as configurações transferidas aqui são imutáveis, ou seja, você não pode alterá-las no processo. Não é necessário tentar, quando algo é reconhecido, substituir o modelo ou o idioma. Dessa forma, não oferecemos aos usuários a oportunidade de alterar o objeto com as configurações que já foram transferidas.

Macros NS_ASSUME_NONNULL_BEGIN / NS_ASSUME_NONNULL_END para enfatizar que essas configurações não podem ser nulas: audioSource não pode ser nula - todas elas devem ter algum valor específico para funcionar.

Como eu disse, os métodos de início e cancelamento (cancelSync à esquerda) foram movidos para um protocolo separado. Há lugares na biblioteca onde você pode usar não o nosso reconnaiser, mas qualquer outro. Por exemplo, usamos o nativo da Apple, que implementa esse protocolo e para o qual ele pode transferir nossos componentes.

As configurações aqui são NSCopying para que possamos copiá-las e elas não puderam ser alteradas no processo. No init, os parâmetros necessários são idioma, modelo e NS_DESIGNATED_INITIALIZER. Este não é um pedaço de código idêntico aos métodos obsoletos, mas a ideia é clara. Estes são parâmetros necessários com os quais as configurações são criadas. Eles devem ser e devem ser diferentes de zero.

O restante do conjunto possui cerca de 20 configurações do reconhecedor aqui. Até as configurações de uma linguagem ou modelo também são classes separadas que não nos permitem transmitir algo abstrato, com o qual não podemos trabalhar. Ou seja, dizemos claramente: “Por favor, não nos dê algo com o qual não sabemos trabalhar. O compilador não permitirá que você faça isso.

Então, conversamos sobre o que você pode fazer com a API. O desenvolvimento também tem suas próprias nuances.

Desenvolvimento


Primeiro de tudo, a biblioteca deve fazer o que você escreveu - para executar bem sua funcionalidade. Mas você pode tornar seu código uma biblioteca muito boa. Proponho várias observações que foram coletadas por mim durante o desenvolvimento do SpeechKit.

O código não é apenas para você


É absolutamente necessário coletar informações de depuração , porque você não deseja que os usuários digam que o serviço deles não está funcionando por causa da sua biblioteca.

O IOS possui um nível de informações de depuração que mostra quais informações precisam ser coletadas. Por padrão, ele coletará absolutamente tudo o que puder encontrar: todas as chamadas, todos os valores. Isso é ótimo, mas é uma quantidade muito grande de dados. Definir apenas tabelas-de-linhas permite coletar informações sobre chamadas de função. Isso é mais que suficiente para encontrar um problema e corrigi-lo.

Isso está incluído nas configurações do Xcode (Build Settings) e é chamado de nível de informações de depuração. Por exemplo, ao ativar essa configuração, reduzimos o tamanho do arquivo binário do SpeechKit de 600 MB para 90 MB. Esta não é uma informação muito necessária e simplesmente a jogamos fora.

A segunda coisa importante é ocultar caracteres particulares . Todos vocês sabem que toda vez que você carrega uma biblioteca no iTunes, corre o risco de receber um novo aviso de que está usando algo errado, sem adicionar nada. Portanto, se você usar bibliotecas que a Apple considera privadas, oculte-as. Isso não significa nada para você, você também pode trabalhar com eles, mas assim que seus usuários tentarem fazer upload do aplicativo com sua biblioteca no iTunes, eles receberão um erro. Nem todos pedirão que você o conserte; a maioria simplesmente se recusará a usar sua solução.

Evite conflitos de personagem : adicione prefixos a tudo o que você tem, às suas aulas, às categorias. Se a biblioteca tiver uma categoria UIColor + HEX, certifique-se de que seus usuários tenham exatamente a mesma categoria e, quando integrarem sua biblioteca, eles receberão conflitos de caracteres. E, novamente, nem todo mundo vai querer dizer e dizer.

Outra pergunta é quando você usa bibliotecas de terceiros em sua biblioteca. Vale a pena lembrar algumas nuances. Primeiramente, se você usar algo que apareceu em uma versão anterior à sua biblioteca, não se esqueça de usar o Link Fraco (Xcode -> Construir Fases -> Vincular Binário Com Bibliotecas -> O status está ativado). Isso permite que você não caia se de repente essa biblioteca não estiver.

A documentação da Apple detalha como isso funciona. Mas a vinculação fraca não significa que a biblioteca não será carregada se não for usada. Ou seja, se a hora de início do aplicativo for importante para seus usuários e você não precisar da parte da sua biblioteca que usa uma biblioteca de terceiros e demora algum tempo para iniciar, a vinculação fraca não ajudará. Com ele, a biblioteca ainda carrega se é usada ou não.

Se você deseja carregar no tempo de execução, isso ajudará a se livrar do problema do link na inicialização, então você precisará usar o dlopen e o carregamento dinâmico. Isso requer muito barulho, e você deve primeiro entender se isso faz sentido. O Facebook tem um código bastante interessante para um exemplo de como eles se vincularam dinamicamente.

Por último - tente não usar entidades globais por dentro . Cada plataforma possui alguns componentes globais. É aconselhável não arrastá-los para a sua biblioteca. Isso parece óbvio porque é um objeto global, e os usuários da sua biblioteca podem pegá-lo e configurá-lo como quiserem. Você o usa na sua biblioteca, precisa salvar de algum modo seu estado, reconfigurar e restaurar o estado. Existem muitas nuances e há onde cometer um erro. Lembre-se disso e tente evitar.

Por exemplo, no SpeechKit, antes da terceira versão, trabalhamos com áudio dentro da biblioteca e configuramos e ativamos explicitamente a sessão de áudio. Uma sessão de áudio no iOS é algo que todo aplicativo possui - não diga que você não tem um. Ele é criado no início, é responsável pela interação do aplicativo e do daemon de mídia do sistema e diz o que seu aplicativo deseja fazer com o áudio. Este é um objeto singleton no sentido mais verdadeiro da palavra. Nós o pegamos com calma, configuramos conforme necessário, mas isso levou ao fato de que os usuários tinham problemas menores, como alterar o volume do som. Outro método de sessões de áudio, responsável por definir as configurações, é bastante longo. Demora cerca de 200 ms, e isso é um abrandamento perceptível na ativação ou desativação.

Na terceira versão, peguei com alegria uma sessão de áudio da biblioteca. Depois disso, quase todos os usuários de todos os serviços que tinham o SpeechKit integrado disseram que estavam terrivelmente infelizes. Agora eles devem saber que existe algum tipo de sessão de áudio que precisa ser especialmente configurada para o nosso SpeechKit.

A conclusão é a seguinte: mesmo assim, tente não usar entidades globais, mas esteja preparado para o fato de que seus usuários nem sempre ficarão felizes com suas decisões.

Tornamos conveniente para os usuários


De que outra forma você pode ajudar seus usuários?

  • Adicionar logs: níveis diferentes, inclusão dinâmica .

A maneira mais fácil é anexar um arquivo, cuja presença é um modo de mega depuração. Realmente ajuda a depurar em uma situação em que seus usuários têm usuários com erro e você precisa entender o que exatamente aconteceu.

  • Suporte todas as versões do sistema operacional do usuário.

Lembre-se de que quando você fala sobre o suporte à versão em uma biblioteca, não é o mesmo que o suporte à versão em um aplicativo comum. Em um aplicativo comum, analisamos as estatísticas de que, por exemplo, apenas 2% de nossos usuários usam o iOS 8, e isso significa que você pode parar de oferecer suporte ao iOS 8. Na biblioteca, não é assim. Recusar a versão do sistema operacional significa abandonar completamente o usuário e todos os usuários. Isso pode ser metade dos seus usuários em princípio.

Portanto, é necessário monitorar quais versões são usadas pelos aplicativos que usam sua biblioteca e, com base nisso, você já deve concluir se oferece suporte a algo ou não. Não recusamos o iOS 7 por um longo tempo. Parece-me que já havia pessoas que abandonaram o iOS 8 e estavam prontas para abandonar o iOS 9. Ainda apoiamos o iOS 7, porque tínhamos um navegador que até o fim mantinha todos os usuários, e trabalhamos em estreita colaboração com ele e não conseguimos deixá-lo em tal situação.

Novamente, seus usuários não dirão: “Vamos desativar essa funcionalidade na versão que não a suporta”, não, eles simplesmente removerão sua biblioteca e encontrarão uma que suporte toda a série de versões.

  • Adicione incremento mínimo em novas versões.

Isso é muito "não muito" para desenvolvedores de bibliotecas. Quero liberar tudo o que está pronto para lançamento. Você criou recursos, corrigiu bugs - agora colocaremos o pacote inteiro e o lançaremos no lançamento. A liberação também é um processo. Isso não é verdade para seus usuários. Quando eles estão testando seu produto e preparando-o para liberação, eles não desejam receber de você um assembly com novos recursos que precisam de testes adicionais.

Realmente tivemos casos em que revertemos alguns lançamentos, os dividimos em partes e os lançamos já em pedaços. Então, as equipes para as quais implementamos alterações podem ter exatamente a versão em que há pequenas alterações, e não todas de uma vez.

Isso realmente não é muito conveniente para o desenvolvimento, mas o incremento mínimo de versões tornará seus usuários um pouco mais felizes.

Nunca há muitos testes


Isso vale tanto para um aplicativo regular quanto para uma biblioteca. Mas no caso da biblioteca novamente, existem recursos.

Certamente, são necessários autotestes , mas além deles é ótimo ter um aplicativo de teste para sua biblioteca. Isso o ajudará a integrar o que você escreveu e a entender quais problemas ou armadilhas podem surgir. Você pode sentir por si mesmo quais são seus usuários.

Se sua biblioteca, de alguma forma, interage com a rede, inclui criptografia, há pelo menos algo relacionado a dados e segurança, entregue a seguranças para verificação . Você absolutamente não quer ser a biblioteca na qual eles encontram a vulnerabilidade - é um estigma para a vida toda. Quase todas as grandes empresas têm um departamento inteiro que lida com a verificação de segurança dos produtos - entregue a eles. Se você não possui uma, há uma auditoria externa . Se você não puder pagar pelo externo, encontre os testes na rede, execute-os, verifique se a sua biblioteca não permite vazamento de dados do usuário.

A última coisa que é muito importante nos testes é, desde o início, tentar adicionar medidas de tudo o que é possível : tempo, consumo de energia, tudo o que é típico para sua biblioteca em particular. Você ainda precisa fazer isso no final, por que não pensar em medidas desde o início.

Isso não protege contra alterações e da necessidade de acelerar a biblioteca, mas ajuda a descobrir o que deu errado. Se você tiver gráficos, isso ajudará no monitoramento em tempo real de quais funcionalidades adicionaram atrasos ou aumento no consumo de energia.

Quase nunca há tempo para isso, porque essa não é a funcionalidade da biblioteca, não é para isso que você a está desenvolvendo. Mas é isso que ajuda a mantê-lo em boas condições e em boa qualidade.

Aqui você pode ler como nós, na Yandex, medimos o consumo de energia de dispositivos móveis. Sobre as medições de tempo foi uma história engraçada. Como desenvolvedores de bibliotecas, é difícil medir o comportamento em casos específicos, porque nem todos os scripts do SpeechKit são usados ​​por todas as equipes. Até o momento, usamos nosso aplicativo de teste. Casos especiais de uso foram escritos, por exemplo, um reconhecedor ou componentes para síntese de fala, todas as etapas foram gravadas e os registros foram salvos e, como resultado, gráficos interessantes foram construídos.

Tudo ficaria bem, mas trabalhamos com áudio e, para verificar tudo, em certos casos a faixa de áudio realmente é reproduzida. Além disso, é necessário fazer muitas medições, para que eles deixem o teste para a noite: coloque os alto-falantes, coloque algum tipo de dispositivo ao lado e inicie os arquivos de áudio. De manhã, tudo desligou, na noite seguinte repetiu e depois novamente. Não se tratava de algumas criaturas mágicas que andavam pelo escritório - apenas os limpadores estavam assustados. Havia realmente um texto muito estranho que era lido em intervalos.

Como resultado, foi decidido fazer um banco de testes local, que chamamos de Gabinete. Este é um gabinete natural, apenas à prova de som. Ele contém muitos dispositivos, um farm inteiro com dispositivos, cada um dos quais pode ser iniciado várias vezes durante o dia útil, porque não fará mal a ninguém.

Lançamento


Finalmente chegamos à última parte importante - este é o lançamento. O código está escrito, uma boa API foi projetada para torná-lo conveniente para os usuários. Como agora para liberar tudo isso em lançamento.

Começarei com lançamentos locais para usuários dentro do Yandex. O esquema aqui é o mesmo que no desenvolvimento de um aplicativo regular: lançamentos regulares, mensais ou semanais.

O processo consiste nas etapas usuais, mas ao desenvolver uma biblioteca, cada um desses pontos tem suas próprias características.

Planejamento


Para mim, essa é a parte mais dolorosa, porque a biblioteca possui várias equipes de produtos. Em um aplicativo regular, há um gerente de produto que define tarefas que a equipe prioriza e começa a executar uma por vez.

Se houver várias equipes de produtos, cada uma delas receberá solicitações que devem ser processadas em tempo real. Vou dar conselhos: se houver uma pessoa que saiba lidar com uma infinidade de tarefas em um momento, tente buscá-la em sua equipe. Porque deve haver alguém entre todos os gerentes externos e o desenvolvimento - aquele que assumirá a funcionalidade para priorizar tarefas.

SpeechKit , , , . , , - . , — . , n . , . , , - .



, , : , , . Agile- .

, , , — . , . !

Scrum . , , , . . « », .

Scrum , , , — — , . . — , - . , ? , : «, , , ». , , - , , Scrum . ! , .

. , , . , . , , , , . , . .



, — , - . , , , , . , . : « 4, 3 — ». , . - , , , , .

. Continuous Integration , , , .



, . .

1. .

. - - , , , . .

. , — , , , , . , , - .

2. .

, , , — , , , , , !

. , . , , -, .

. SpeechKit . , , — , - . — , - .

, . , 4 2, , . , -, , .

. , , , .

. .


, -, . . , , , help , .

. : -, GitHub, , . — , — . , , .

, , - , , ..



, , :

  • . , . - , , .
  • . , . , OpenSource , , , , .
  • . , . , , . . SpeechKit .

Sumário


  • , API.
  • , , .
  • .
  • , - :) - , .

Yandex.SpeachKit GitHub iOS , Android , Mobile SDK.

AppsConf — — 22 23 2019 , , .

. , , .

Source: https://habr.com/ru/post/pt429912/


All Articles