Skip to content

theomendes/challenge-alpha

 
 

Repository files navigation

Desafio Alpha

Por: Theo Mendes < [email protected] >.

1. Conteúdo

2. O Projeto

Arquitetura: MVVM-C

Aviso: Ao olhar o historico de commits poderá ver que tem um "outro" contribuidor no projeto, isso se deve ao fato que sem querer ao codar em um outro computador meu, esqueci de verificar o config do git, logo esses 3 commits ficaram como autoria da minha conta antiga no GitHub, na qual não tenho mais acesso.

A escolha resta arquitetura deve-se ao fato de ser bastante testável mas ainda ter um nível de simplicidade que pode ser rapidamente estruturado. Implementei um Coordinator pois isso é uma das coisas que falta no MVVM uma camada de routing.

O projeto é separado em 3 Schemas: Debug, AdHoc e AppStore e 3 Build Configurations: Development, Production, Stage, tem uma bundle id, nome e ícones diferentes para cada Build Configuration, para assim em um único aparelho poder se instaladas cada versão, o nome e ícone são para mera diferenciação visual.

O projeto para evitar erro humano automaticamente detecta para qual schema esta buildando e pega as variáveis de ambientes de acordo, por exemplo você pode querer durante o desenvolvimento usar o localhost como url para consumir uma API, e uma url real para o app em produção. Para assim evitar que haja chance de acabar indo uma url de desenvolvimento para produção.

Usei tanto o CocoaPods, como Carthage. Fiz essa escolha pois como o Carthage compila os frameworks quando você pega eles, isso faz diminuir consideravelmente o tempo de compilação do projeto todo, assim aumentando a produtividade. Usei o CocoaPods somente pelo fato que nem tudo esta no Carthage, principalmente dois grandes frameworks muito usados: SwiftLint e SwiftGen.

Resolvi não implementar tela de detalhe de um produto por questão de escopo, resolvi focar na organização do feed e do projeto.

3. Logs

Para realização de logs eu utilizei o os.log assim fica mais fácil de visualizar eles em ferramentas de analise de log, eu abri uma issue perguntando sobre o log da resposta da api, mas como não obtive resposta até o termino do desafio, fiz a escolha de imprimir no console.

3.1. Significado no console

  • 👶 -> Init
  • ⚰️ -> Deinit
  • 🧠 -> View Model
  • 🧭 -> Coordinator
  • 🎮 -> View Controller
  • 🔲 -> Table View Cell
  • 🏻 -> Collection View Cell
  • 📶 -> Network
    • ⬇️ -> Receiving
    • ⬆️ -> Sending
    • ✅ -> Status Successful
    • ⚠️ -> Status Failure

4. Instalação

4.1. Prepare o ambiente

Para rodar este projeto você irá precisar do Ruby Bundler, Carthage e CocoaPods

Carthage pode ser instalado rodando o seguinte comando:

brew update
brew install carthage

O Bundle deve ter vindo junto com a instalação do Ruby. Você precisa do Ruby maior que 2.4. Se você não tem o bundle, pode ser instalado rodando o seguinte comando:

sudo gem install bundler

4.2. Configuração do projeto

  1. Na pasta Root do projeto rode
bundle install
  1. Rode a instalação do CocoaPods
bundle exec pod install
  1. Rode o Carthage
carthage bootstrap --platform ios --cache-builds --no-use-binaries

5. Design

5.1. Feed

Como o desafio não impunha um design especifico do feed, preparei algumas telas. Não quis seguir com o exemplo de tabulação dado no README do desafio pelo de ter ja de cara um problema de UX, o usuário para ir até a informação que precisa precisa escrolar muito, como por exemplo, se ele quiser procurar um hotel 3 estrelas, na tabulação de exemplo ele teria que percorrer um grande caminho e poderia até desistir da compra.

Analisando o app de vocês para iOS e o site, para mim ficou claro que vocês valorizam dar destaque para o local e o preço atrativo. Seguindo esta ideia resolvi aplicar um feed com sessões laterais, dentro das sessões laterais eu ordenei decrescente pela porcentagem de desconto, logo os hotéis que acabaram de ter desconto ficam por ultimo.

Percebi que a Hurb da bastante valor para os pacotes, levando em conta isso resolvi colocar os pacotes como a primeira coisa do feed e dando bastante destaque para foto.

Preparei também 2 telas extras, uma de carregando e outra de quando deu erro, por questão de escopo não preparei métodos para se recuperar do erro.

Feed Design

Icons

6. Toque a mais

Ao invés de implementar telas extras resolvi somente focar no desenvolvimento do feed, para assim criar um feed bem conceituado e um projeto bem configurado

6.1. Configurei o projeto de maneira segura para diversos ambientes, Dev, AdHoc e AppStore.

Isso mantem a consistência do projeto entre os colaboradores, não precisando ficar mudando strings de API antes de dar um push, por exemplo, ou até mesmo ao mandar para a AppStore.

6.2. Exibo além do preço atual, o desconto atual do local.

Pela análise tanto do app como site vi que uma coisa que vocês valorizam é o preço atrativo, então adicionar essa lógica me pareceu interessante.

6.3. Dentro das seções são ordenadas pela porcentagem do desconto

Com isso eu crio um destaque para os maiores descontos, e consequentemente o item que o desconto acabou de finalizar tem menos prioridade no feed.

6.4. Uso células diferenciadas para o Hotel e Pacotes

A Hurb valoriza os seus pacotes, então colocando eles na primeira parte do feed, e com elementos diferenciados do hotel, crio um destaque para eles.

6.5. Feed centrado na experiência do usuário

O usuário acha rapidamente a informação que ele quer, como o Preço, facilidades, local e estrelas.

6.6. Auto Layout, a célula de pacote se adapta a largura do celular, mantendo aspect ratio.

A célula fica proporcional para qualquer dispositivo, e as de hotel sempre ficam no centro da tela.

6.7. Localização do app tanto em Inglês quanto Português.

Como a Hurb esta em um processo de internacionalização, é uma obrigação do app se adaptar aos locais que ele vai está disponível. Isso incluindo o preço, como por exemplo em en_US 3,000.00 em pt_BR 3.000,00. Mas tomei cuidado com o fato da API retornar a currency que o preço esta, então independente do caso vai sempre aparecer o símbolo como R$.

6.8 Implementação de tela de loading e erro

7. Testes

Total de cobertura: ~88% pelo XCode

7.1. Unitários

Criei testes unitários para o ViewModel e o Network layer, usei um stub em formato json para mockar a resposta da API, para assim garantir a consistência dos dados. o stub criei de uma resposta da API da Hurb, mas deletei alguns objetos para garantir a diferença entre a API real para o stub (So para fim de testes de objetos retornados).

7.2. UI

Pelo fato do app conter uma tela eu testei o scroll vertical, e swipe em duas sessões.

8. Dependências

Uso ele para garantir consistência entre as versões do cocoapods dos contribuidores do projeto, assim evitando problemas no Podfile.lock e consequentemente no workspace.

8.2.1. SwiftLint

Creio que em grandes projetos tem que haver uma maneira de garantir que as regras de boas práticas sejam compridas, então não há escolha melhor que esta.

8.2.2. SwiftGen

Um dos grandes problemas, principalmente em assets, é garantir que eles sejam type-safe, escolhi ele para garantir que os Assets e arquivos de Localização fiquem todos type-safe.

8.3.1. RxSwift

O forte do MVVM é a ligação entre a View e ViewModel, então bibliotecas reativas são muito bem vindas. Eu fiquei em duvida entre usar ele ou ReactiveSwift, ReactiveSwift esta presente a mais tempo no mundo Reativo do Swift e ele se aproxima mais a guidelines do Swift do que resto do mundo, por outro lado RxSwift se aproxima ao framework ReactiveX que esta disponível em diversas plataformas logo tenta manter uma guideline padrão, creio que em um lugar como a Hurb com diversas linguagens de desenvolvimento seja mais atrativo manter um padrão entre elas.

Uma falha no RxSwift é que ele não facilita a construção de feeds mais complexos que simples colections views ou table views, com isso para facilitar o trabalho resolvi usar ele.

8.3.3. Moya

Uma das grandes dificuldades em network layer é garantir que ele seja altamente testável, escolhi o Moya por ele ser construído em cima do Alamofire, que ja esta a muito tempo presente no Swift, ser altamente testável e type-safe.

8.3.4. SnapKit

Ficar escrevendo constraints é um trabalho que demanda um certo tempo, e de não ser muito bonito em escrever, SnapKit facilita bastante mas ainda se assemelha muito a lógica da constraint nativa.

8.3.5. Kingfisher

Kingfisher oferece maneiras eficientes de fazer o download de imagens e guardar em cache, evitando que a pessoa tenha sempre que fazer download de imagem, assim aumentando a responsividade do app e economizando gets na AWS ou outro serviço de hospedagem, o que significa menos $$ gasto.

9. Vulnerabilidades

9.1. Moya - Beta

Não sei se é considerado uma vulnerabilidade, mas pelo fato de estar usando Swift 5.1 o Moya não atualizou certas dependências dele na versão estavel, tal como o ReactiveSwift que ainda esta na versão anterior assim não compilando. Com isso tive que usar a versão 14 Beta 4 do Moya.

9.2. Imagens das celulas de collection view - HTTPS

No HotelCollectionViewCell.swift e PackageCollectionViewCell.swift tive que forçar o uso de HTTPS no link das imagens, ja que alguns domínios vinham da API usando protocolo HTTP, nos casos que analisei que não vinham como HTTPS, vinham com o domínio: omnibees.com, fiz uma checagem e vi que ele era compatível com HTTPS, logo por questões que a própria Apple impõe em aplicativos de produção, tive que forçar o HTTPs, mas como não conheço a API da Hurb não posso afirmar com certeza que todos os links vem da omnibees ou AWS, logo pode haver casos que a imagem não apareça no feed.

About

Desafio mobile

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Swift 96.7%
  • Ruby 3.0%
  • Shell 0.3%