Skip to content

Boas práticas que a IlhaSoft recomenda em projetos iOS

Notifications You must be signed in to change notification settings

Ilhasoft/iOS-Boas-Praticas

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 

Repository files navigation

Boas Práticas no Desenvolvimento iOS

Assim como software, este documento também deve ser mantido pelos desenvolvedores. Desta forma, poderemos ter a garantia de que ele estará sempre atualizado com as nossas necessidades e costumes diários. Convidamos todos a nos ajudarem nisto - abra uma issue ou mande um pull request.

Motivação

Sabemos que pode ser difícil mergulhar de cabeça no mundo iOS. A estrada pode ser longa e tortuosa da construção até o lançamento dos aplicativos na AppStore. Mas não se desespere! Foi por isso que criamos este documento. Ele tem como objetivo ajudar aos iniciantes e servir como guia aos desbravadores que sempre pensam e procuram fazer as coisas da "maneira correta". Tudo que escrevemos aqui são sugestões de boas práticas, mas caso tenha uma boa razão para fazer as coisas de maneira diferente, te encorajamos a seguir em frente!

Conteúdo

Se estiver procurando por algo específico, pode ir diretamente à seção.

  1. Getting Started
  2. Criando um novo projeto
  3. Criando um novo layout
  4. Dependency Management
  5. Coding Style
  6. Stores
  7. Segurança
  8. Diagnósticos
  9. Analytics
  10. Building
  11. Deployment
  12. In-App Purchases (IAP)
  13. Referência
  14. License

Getting Started

Linguagens de Programação

Utilizamos sempre a versão mais recente do Swift. Recomendamos uma boa lida na documentação oficial para entender as particularidades da linguagem. Em alguns casos, algum conhecimento em Objective-C pode vir a ser útil.

Human Interface Guidelines

Se você não está acostumado ou vem de outra plataforma, tire um tempo para se familiarizar com o conteúdo das Human Interface Guidelines. Estas guidelines possuem uma bom explanação dos componentes UI nativos e suas nomeclaturas, dimensões dos ícones etc.

App Framework

Recomendamos a utilização do Apple Developer Documentation sempre que necessário.

IDE

Usamos o Xcode como IDE para construir os aplicativos, pois é a IDE recomendada pela Apple e possui o melhor suporte a Objective-C e Swift.

Criando um novo projeto

Versão mínima do iOS

É sempre útil que façamos uma avaliação prévia antes de escolher qual a versão mínima do iOS que vamos utilizar ao criarmos um novo aplicativo. Isso porque muitas vezes temos que prestar atenção em funcionalidades que surgem a cada versão e precisamos estar de olho. Regra geral: costumamos criar sempre projetos onde a versão mínima do iOS seja duas versões a menos que a atual.

Use essas ferramentas para colher informações para fazer a melhor escolha:

Localization

Mantenha todas as strings em arquivos de localization desde o início do projeto. Essa prática não é somente boa para traduções, mas torna mais fácil a busca por textos visíveis ao usuário.

Constantes

Mantenha o escopo das constantes o menor possível. Por exemplo, caso você precise das constantes somente dentro de uma determinada classe, as constantes devem estar definidias dentro desta classe. Àquelas constantes cujos escopos devem ser globais devem ser mantidas em um só lugar. Em Swift, você deve usar enums definidos em um arquivo chamado Constants.swift para agrupar, armazenar e acessar as constantes globais de uma maneira prática e elegante:

enum Config {
    static let baseURL = NSURL(string: "http://www.example.org/")!
    static let splineReticulatorName = "foobar"
}

enum Color {
    static let primaryColor = UIColor(red: 0.22, green: 0.58, blue: 0.29, alpha: 1.0)
    static let secondaryColor = UIColor.lightGray

    // A visual way to define colours within code files is to use #colorLiteral
    // This syntax will present you with colour picker component right on the code line
    static let tertiaryColor = #colorLiteral(red: 0.22, green: 0.58, blue: 0.29, alpha: 1.0)
}

Ignores

Um bom passo a ser tomado quando colocamos um projeto em um controle de versão é usarmos um .gitignore apropriado. Desta forma, arquivos não desejados (user settings, arquivos temporários, etc) nunca poluirão o repositório. Por sorte, o Github nos proporciona arquivos .gitignore por default para tanto Swift quanto Objective-C. Caso deseje um .gitignore mais elaborado, indicamos a ferramenta gitignore.io.

Criando um novo layout

Por que criar layouts inteiramente via código?
  • Os storyboards são mais propensos a gerarem conflitos devido a estrutura complexa do seu XML. Isto faz com que os merges sejam mais difíceis do que se criássemos a view totalmente via código.
  • É mais fácil estruturar e reusar views que sejam feitas via código, mantendo assim o seu código DRY (Don't Repeat Yourself).
  • Toda informação está em um só lugar. No Interface Builder você deve buscar em todos os inspectors afim de achar o que você estiver procurando.
  • Os storyboard introduzem uma certa acoplação entre seu código e a UI que pode levar a diversos erros. Por exemplo: quando um IBOutlet ou IBAction não é configurada corretamente. Estes erros não são detectados pelo compilador.
Por que utilizar XIBs ao invés de Storyboards?
  • Como a estrutura do XML dos XIBs é menos complexa do que a estrutura XML de storyboards, a possibilidade de que hajam conflitos de merge é diminuída.
  • A possibilidade de criar o XIB de componentes independentes aumenta a reusabilidade, o que por consequência mantém o princípio DRY.
  • A possibilidade de pré-visualizar os componentes e ter uma visão mais próxima de como ele irá se comportar em um dispositivo.
Aproveitando o melhor dos dois mundos

Você também pode utilizar o modo híbrido: comece criando um rascunho da tela no XIB, isso faz com que pequenas mudanças de layout se tornem mais fáceis e rápidas. Neste processo, você também pode chamar os designers para participarem da criação. Assim que o UI amadurecer, você pode alternar para uma abordagem mais voltada ao código afim de introduzir a lógica do negócio.

Dependency Management

Aqui temos algumas possíveis ferramentas caso você esteja planejando incluir bibliotecas de terceiros em seu projeto. Elas estão ordenadas de acordo com a prioridade de uso em nossos projetos. Geralmente seguimos a seguinte prioridade: Cocoapods > Carthage > Vendors.

Cocoapods

Devido a sua simplicidade, o Cocoapods oferece uma integração bastante fácil e rápida. Instale-o com o seguinte comando:

sudo gem install cocoapods

Para iniciar, acesse o diretório de seu projeto via terminal e digite:

pod init

Este comando criará o arquivo Podfile que será responsável por agrupar todas as bibliotecas que serão utilizadas no projeto em um só lugar. Depois que você adicionar as bibliotecas no Podfile, execute no terminal o seguinte comando:

pod install

Este comando incluirá as bibliotecas como parte do workspace de seu projeto. Geralmente é recomendado dar commit nas dependências instaladas do seu repositório ao invés de que cada desenvolvedor execute pod install depois de um novo checkout.

Perceba:

  • A partir de agora você terá que utilizar o arquivo .xcworkspace ao invés de .xcproject ou seu projeto não compilará.
  • O comando pod update atualizará todos as dependências em suas últimas versões permitidas pelo Podfile. Você pode usar alguns operadores para especificar quais versões das bibliotecas seu projeto deverá utilizar.

Vendors

Caso o componente que você deseja incluir no projeto não esteja disponível no Cocoapods e nem no Carthage, te aconselhamos a adicioná-lo ao código base do projeto em um diretório chamado Vendors.

⚠️ IMPORTANTE ⚠️

  • Lembre de ler, avaliar e adicionar a licença de software (caso haja) aos arquivos do componente que estiverem presentes em seu projeto, dando os devidos créditos ao autor e incluindo uma url fonte para facilitar futuras buscas.
  • Como não existirá um Dependency Manager vinculado ao componente, fique atento! Será responsabilidade da sua equipe manter esta parte de código. Aconselhamos a não incluir algo que não consigamos compreender.
  • SUGESTÃO: Caso seja feita alguma mudança/melhoria ao código, lembre-se de compartilhá-la junto ao projeto de origem. Apreciamos a contribuição em projetos open-source.

Libs mais utilizadas

Coding Style

Idioma

Preferimos sempre utilizar o idioma inglês ao criarmos nossos projetos.

Lint

Procuramos seguir sempre boas convenções de código. Para tanto, utilizamos o SwiftLint como ferramenta a nos auxiliar nesta missão. O SwiftLint age como um agente inspecionando o nosso código em busca de bad smells e nos alertando que algo não está tão legal com warnings providenciais.

Para instalar o SwiftLint, siga as instruções em sua documentação.

Recomendamos também uma boa lida nas Code Conventions de Ray Wenderlich.

Documentação

Pregamos o bom senso com relação a documentação de código. Procuramos prevenir a necessidade de documentações extensas ao criarmos códigos legíveis. Entretanto, fique à vontade Caso haja a necessidade de explicar alguma decisão tomada. Pense sempre que seus amigos ficarão mais felizes por não precisarem perder tempo tentando entender o código que foi feito por você.

Consideramos que o autores do NSHipster fizeram um bom trabalho ao definir como formatar a documentação. Recomendamos uma lida no material deles sempre que necessário. 😉

Stores

ReactiveCocoa

Na camada mais baixa de todo aplicativo geralmente os modelos são mantidos de alguma maneira, seja em um banco de dados local ou em um servidor remoto. Esta camada também é útil para abstrair atividades relacionadas com a disposição de objetos do modelo.

Geralmente quando desejamos lançar uma requisição ao backend ou deserializar um grande arquivo em disco, fazemos isto de maneira assíncrona. Sua API deve refletir este requisito, caso contrário a execução de seu app seria interrompida enquanto não houvesse resposta das requisições a API.

Se você está usando ReactiveCocoa, SignalProducer é uma escolha natural de tipo de retorno. Por exemplo, se quiséssemos requisitar as gigs de um artista, faríamos como o seguinte código em Swift e ReactiveSwift:

func fetchGigs(for artist: Artist) -> SignalProducer<[Gig], Error> {
    // ...
}

Veja que o SignalProducer é somente uma forma de receber uma lista de gigs. Somente quando iniciado pelo subscriber ele irá realmente fazer a requisição dos gigs. Dar unsubscribe antes que os dados tenham sido recebidos cancelará a requisição.

⚠️ Se você não deseja utilizar signals, futures ou mecanismos similares para representar seus dados futuros, você pode sempre utilizar blocos de callback. Mas tenha em mente que o encadeamento ou aninhamento destes blocos pode rapidamente se torna difícil de manter - condição a qual chamamos de callback hell. ⚠️

Segurança

Mesmo em tempos onde confiamos nossos dados mais particulares aos nossos dispositivos portáteis, a segurança nos aplicativos continua sendo algo frequentemente negligenciado. Tente achar um bom trade-off dada a natureza de seus dados seguindo somente algumas regras que listaremos a seguir. Um bom material para iniciar é a iOS Security Guide criada pela própria Apple.

Data Storage

Caso seu aplicativo precise manter no dispositivo dados sensitivos, como nome de usuário e senha, auth token ou dados pessoais do usuário, você precisa mantê-los em um local que não possa ser acessado de fora do app. Nunca use UserDefaults, outros arquivos plist no disco ou Core Data para este fim porque eles não podem ser encriptados! Na maioria dos casos, o iOS Keychain será seu melhor amigo.

Enquanto estiver mantendo arquivos e/ou senhas, esteja seguro de determinar o nível de proteção correto (escolha-o conservadoramente). Se você precisa ter acesso enquanto o dispositivo estiver bloqueado, use accessible after first unlock. Em outros casos, você geralmente deve só liberar o acesso quando o dispositivo tenha sido desbloqueado.

⚠️ Só mantenha dados sensitivos quando realmente necessário! ⚠️

Networking

Mantenha encriptado com TLS todo o tráfego HTTP do aplicativo ao servidor remoto. Para evitar ataques man-in-the-middle que interceptem seus dados encriptados, você pode configurar um pinning certificate. Bibliotecas populares como AFNetworking ou Alamofire já o suportam out-of-box.

Logging

Tome um cuidado extra ao configurar apropriadamente níveis de log (dica: utilize a lib CleanroomLogger) antes de lançar seu app. Builds em produção não devem nunca dar log em senhas, tokens de API ou similares, porque são dados sensitivos e podem vazar ao público facilmente. Por outro lado, dar log no controle de fluxo pode ajudar a descobrir problemas que seus usuários estão experenciando.

User Interface

Quando estiver usando um UITextField para inserção de senha, lembre de configurar sua propriedade secureTextEntry para true para evitar que a senha esteja visível. Você também deve disabilitar o corretor automático e limpar o campo sempre que apropriado, como quando seu app entra em background.

Quando isto acontecer, é uma boa prática limpar o Pastboard para evitar que o password seja descoberto de alguma maneira. Como o iOS tira screenshots para dispôr no App Switcher, esteja seguro de limpar qualquer dado sensitivo no UI antes de retornar do applicationDidEnterBackground.

Diagnósticos

Warnings do Compilador

Habilite todos os warnings do compilador e os trate como se fossem erros - vai valer a pena.

Para tratar warnings como erros em Swift, adicione -warnings-as-errors às configurações de compilação.

Clang Static Analyzer

O compilador CLang (utilizado pelo Xcode) tem um analisador estático que analisa o fluxo de dados e de controle do seu código e detecta inúmeros erros que o compilador não é capaz.

Você pode executar manualmente o analisador a partir do item de menu no Xcode: Product -> Analyze.

O analisador consegue trabalha em dois modos diferentes: swallow e deep. O modo deep é executado mais demoradamente que o modo swallow por conta de sua varredura profunda.

Recomendações:

  • Habilite todos os checks do analisador.
  • Habilite o Analize during 'Build' na configuração de compilação de release para que o analisador seja executado automaticamente após a compilação de releases.
  • Configure o campo Mode of Analysis for 'Analysis' da configuração de compilação para shallow.
  • Configure o campo Mode of Analysis for 'Build' da configuração de compilação para deep.

Debugging

Quando seu app falha o Xcode não abre o debugger por padrão. Para que isto aconteça, adicione um breakpoint de exceção (clique no "+" no fundo da Navigator de breakpoints do Xcode) para interromper a execução sempre que uma exceção for lançada. Isto irá capturar qualquer exceção, até mesmo as que já são tratadas.

Profiling

O Xcode vem com uma suite de análise de perfomance chamada Instruments. Ela contém uma infinidade de ferramenta para análise de uso de memória, cpu, rede, gráficos e muito mais. É de uma complexidade só! Mas um de seus casos mais simples é buscar memory leaks utilizando o instrumento Allocations: aperte o botão Record e filtre o sumário em alguma string útil, como o prefixo do nome das classes do seu app. A contagem da coluna Persistence te diz quantas instâncias de cada objeto você tem. Qualquer classe a que mostre o aumento indiscriminado na contagem indica memory leaking.

Analytics

Incluir algum framework de analytics em seu app é extremamente recomendado já que ele te permite ter insights sobre como as pessoas realmente o utilizam. Aquela feature realmente agrega valor? O botão X é ruim de clicar? Para responder essas perguntas, você pode enviar eventos, timings e outras informações mensuráveis para um serviço que as agrega e oferece uma visualização simples.

Exemplos:

Crashlytics

Da mesma maneira, também é interessante que se acompanhe os erros que os usuários do seu app podem estar experimentando. Para tanto, é recomendado o uso de alguma ferramenta de rastreio de erros como o Crashlytics by Fabric.

Building

Esta seção contém um overview deste tópico - caso necessidade de mais informações, dê uma olhada nos seguintes links:

Configurações de Build

Até aplicativos simples podem ser feito de formas diferentes. A separação mais básica que o Xcode nos provê é a separação entre builds de debug e release. Para o último, existem muitas otimizações que são executadas em tempo de compilação. A apple sugere que você utilize as configurações de debug para desenvolvimento e crie seus pacotes da App Store utilizando as configurações de release. Essa é a configuração padrão do Xcode, que executa a build debug quando o comando Run é executado e executa a build release quando o comando Archive é utilizado.

Entretanto, isso é muito simples para aplicações no mundo real. Você pode (ou melhor, deve!) criar diferentes environments para testing, staging e outras atividades relacionadas ao seu serviço. Cada um deles deve ter sua própria URL base, log level, bundle identifier (assim você as pode instalar ao mesmo tempo), provisioning profile e etc.

Targets

Um target reside conceitualmente abaixo do nível do projeto, ou seja, um projeto pode ter vários targets que podem substituir as configurações do projeto. Por exemplo, cada alvo corresponde a "um aplicativo" no contexto de sua base de código. Por exemplo, você poderia ter aplicativos específicos de país (construídos a partir da mesma base de código) para App Store de diferentes países. Cada um deles precisará de builds para development, staging e release.

Schemes

Os Schemes dizem ao Xcode o que deve acontecer quando você clicar nas ações Run, Test, Profile, Analyze ou Archive. Basicamente ele mapeia quais ações devem ser executadas em quais target ou build configurations. Você também pode lançar argumentos, como o idioma em que o app deve ser executado ou configurar flags para diagnóstico ou debugging.

Deployment

Fazer o deploy de um app na AppStore não é exatamente simples. Com isto em mente, aqui vão alguns conceitos centrais que, desde que estejam entendidos, te ajudarão bastante com isso.

Signing

Sempre que você quiser rodar um aplicativo em um dispositivo físico, você precisará assinar sua build com uma certificado gerado pela Apple. Cada certificado está atrelado à uma chave privada/pública, onde a parte privada está armazenada no keychain de seu mac. Existem dois tipos de certificados:

  • Development certificate: Cada desenvoledor do time tem o seu próprio certificado, que será gerado a partir de uma requisição. O Xcode pode resolver isso pra você, mas é melhor não apertar no botão Fix issue e entender o que realmente está acontecendo. Este certificado é necessário para instalar development builds em dispositivos.
  • Distribution certificate: Podem ser vários, mas é melhor que seja mantido um certificado por organização e que se compartilhe sua chave em um canal interno. Este certificado é necessário para que se possa fazer deploy à AppStore.

Provisioning

Além dos certificados, também existem os Provisioning Profiles, que são basicamente o link que faltava entre os dispositivos e certificados. Da mesma forma, existem dois tipos que distinguem entre proprósitos de desenvolvimento e distribuição:

  • Development provisioning profile: Contém uma lista com todos os dispositivos que estão autorizados a instalar e executar o app. Ele está conectado a um ou mais development certificates, um para cada desenvolvedor que estiver autorizado a utilizar o perfil.

  • Distribution provisioning profile: Existem três tipos de distribuição, um para cada caso de uso. Cada perfil de distribuição está atrelado a um certificado de distribuição e será inválidado quando o mesmo expirar.

    • Ad-hoc: Assim como os perfis de desenvolvimento, ele contém uma lista com todos os dispositivos autorizados a instalar o app. Este tipo de profile pode ser utilizado para beta testings para até 100 usuários por ano.
    • App Store: Este profile não tem lista de dispositivos autorizados, já que toda e qualquer pessoa pode instalar aplicativos a partir do canal oficial de distribuição de aplicativos da Apple.
    • Enterprise: Assim como a AppStore, este perfil não tem lista de dispositivos autorizados. Desta forma, toda pessoa com acesso à "AppStore" da empresa pode instalar o app. Este perfil está somente disponível para contas empresariais.

Para sincronizar todos os certificados e perfis da sua máquina, vá em Accounts nas Preferências do Xcode, adicione o seu Apple ID caso necessário e double-click no nome do seu time. Existe um botão de refresh no fundo da tela, você precisa reiniciar o Xcode para que as atualizações apareçam.

Uploading

iTunes Connect é o portal da Apple para gerenciar seus apps na AppStore. Para fazer o upload de uma build, o Xcode pede o Apple ID do desenvoledor. Isto pode tornar as coisas um pouco obscuras quando você fizer parte de um grupo de desenvolvedores e deseja publicar seus apps. Isso acontece porque, por razões misteriosas, todo e qualquer Apple ID só pode estar ligado a uma única só conta no iTunes Connect.

Depois de fazer o upload da build, seja paciente porque pode demorar mais ou menos uma hora até que seu app apareça na seção de builds da versão do seu app. Quando ele aparecer, você pode conectá-lo à versão do app e submetê-lo ao review.

In-App Purchases (IAP)

Quando validar recibos de compras dentro do aplicativo, lembre de garantir os seguintes itens:

  • Autenticidade: O recibo vem da Apple.
  • Integridade: O recibo não foi adulterado.
  • O app coincide: A identificação do pacote do app no recibo coincide com o identificador do pacote da aplicação.
  • O produto coincide: A ID do produto no recibo corresponda ao seu identificador de produto esperado.
  • Novo recibo: Você não recebeu o mesmo ID de recibo antes.

Sempre que possível, configure seu IAP (In-App Purchase) de forma a guardar o conteúdo para venda no lado do servidor e somente entregue ao seu cliente em troca de um recibo válido onde todos os itens abaixos tenham sido verificados. Este tipo de configuração frustra mecanismos de pirataria comuns e - já que a validação é feita no lado do servidor - permite que você use o serviço de validação HTTP de recibos da Apple ao invés de fazê-lo a mão.

Para mais informações a respeito deste tópico, leia a seguinte matéria: Futurice blog: Validating in-app purchases in your iOS app.

Referência

Este documento baseia seus tópicos aos abordados em Good ideas for iOS development by Futurice developers, mas foi traduzido e adaptado para estar de acordo com as práticas utilizadas pelos desenvolvedores da Ilhasoft.

License

Futurice • Creative Commons Attribution 4.0 International (CC BY 4.0)

About

Boas práticas que a IlhaSoft recomenda em projetos iOS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published