GraphQL + Rails na prática – Configurando

GraphQL é uma linguagem de busca que é exposta através de uma API e é executada no lado do servidor através de um sistema de tipos fácil de utilizar. Nessa série de posts vamos ver como podemos criar e servir uma API com GraphQL utilizando Rails.

O que você vai precisar:

  • Ruby configurado (a versão mais recente utilizada aqui é a 2.5.0)
  • Rails instalado (a verão mais recente utilizada aqui é 5.1.5)
  • Uma tesoura sem ponta

Configurando o Rails

Vamos utilizar um projeto Rails API já que não vamos expor nenhum conteúdo visual, só a API GraphQL mesmo. O nosso projeto vai expor informações sobre jogos e as personagens que participam nele, então execute

rails new graphql-games --api

Agora vamos adicionar a dependência com o GraphQL no Gemfile. Basta adicionar ao final do arquivo (ou na ordem que preferir) e instalar via bundler

# Gemfile
gem 'graphql'

# Terminal
bundle

A página do GitHub da gem possuí bastante informação e detalhes sobre o funcionamento. Agora que o GraphQL foi adicionado, vamos gerar o código que vai lidar com as consultas na nossa aplicação:

bundle exec rails generate graphql:install

Se a instalação ocorreu sem problemas, você deve conseguir ver uma nova pasta dentro de ‘app’ chamada ‘graphql’. Nela serão definidos os tipos que vamos utilizar para expor as informações sobre jogos (vamos entrar em mais detalhes daqui a pouco).

A instalação da gem vai criar um tipo chamado ‘testField’ em ‘app/graphql/types/query_type.rb’.

O que é um GraphQL Type?

Da mesma forma que ao utilizar expor dados via REST criamos endpoints específicos para cada recurso, em GraphQL montamos um grafo para expor os recursos e seus relacionamentos (daí podemos percorrer esse dado com a linguagem de busca). Cada nó desse grafo é representado por um tipo que define campos, que por sua vez podem se referir a outros tipos.

O código gerado deve parecer com isso:

# app/graphql/types/query_type.rb
Types::QueryType = GraphQL::ObjectType.define do
  name "Query"
  field :testField, types.String do
    description "An example field added by the generator"
    resolve -> (obj, args, ctx) {
     "Hello World!"
    }
  end
end

O tipo definido no arquivo ‘query_type.rb’ são os tipos expostos no começo do grafo, no caso temos um campo chamado ‘testField’ que retorna “Hello world!” (dentro do bloco ‘resolve’). Para ver o que acontece na prática utilize o GraphiQL App apontando para http://localhost:3000/graphql e execute a query:

query {
  testField
}

Screen Shot 2018-02-18 at 07.42.27

O que aconteceu?

O código definido no campo ‘testField’ foi executado e o servidor retornou um JSON contendo “Hello World!”. Como GraphQL é exposto através de um endpoint ao instalarmos a gem foi criada uma rota para ‘/graphql’ e um controller chamado ‘GraphQLController’ em ‘app/controllers/graphql_controller.rb’.

Olhando melhor esse código (que foi gerado) vemos que algumas variáveis são definidas e ao final do método ‘#execute’ é feita uma chamada para ‘GraphqlGamesSchema.execute’

# app/controllers/graphql_controller.rb
result = GraphqlGamesSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result

O objeto ‘GraphqlGamesSchema’ é definido em ‘app/graphql/graphql_games_schema.rb’ e ele é na verdade um ‘GraphQL::Schema’ que define mutations e queries.

# app/graphql/graphql_games_schema.rb
GraphqlGamesSchema = GraphQL::Schema.define do
 mutation(Types::MutationType)
 query(Types::QueryType)
end

Lembra que o ‘testField’ é definido no ‘Types::QueryType’ em ‘# app/graphql/types/query_type.rb’? Então, é assim que chegamos até ele, daí será executado o ‘resolve’ e a string “Hello World!” é retornada. O método ‘resolve’ precisa retornar uma string pois esse foi o tipo definido ao criarmos o campo:

# app/graphql/types/query_type.rb

field :testField, types.String do

Nos próximos posts vamos criar modelos no Rails e ver como é fácil utilizar GraphQL para expor os dados. Se você curtiu conhecer mais sobre GraphQL avisa lá no twitter e fica ligado nos próximos posts!

Anúncios

3 coisas que aprendi ao trabalhar com Cloud Native Applications

A internet é uma novidade que veio pra ficar, mesmo. Trabalhar com uma arquitetura nativa na nuvem é bem diferente, mesmo já trabalhando com microserviços.

Nos últimos 6 meses eu trabalhei em um projeto bem legal de construção de uma plataforma digital para criação de APIs e aplicações com arquitetura nativa na nuvem e nesse post vou compartilhar 3 coisas que aprendi e que podem ser úteis pra quem estar indo por esse mesmo caminho.

Se você gostar desse post, avisa lá no Twitter ou deixa um comentário que eu escrevo outros entrando em mais detalhes em cada um desses conceitos.

A sua pipeline não será mais a mesma

Aquela ideia de clonar o repositório e rodar os testes muda um pouco já que provavelmente as aplicações serão encapsuladas dentro de um container. Ao invés de clonar o repo você deve baixar a imagem e rodar os testes dentro de um container, o que ajuda a reduzir as diferenças entre ambientes.

Mas já passei por algumas dores de cabeça quando os testes passavam localmente, mas falhavam na pipeline (ambos rodando dentro de um container). Ao lidar com Docker é preciso estar atento as tags das imagens, volumes e imagens antigas que possam “poluir” e criar diferenças entre a pipeline e seu ambiente.

Ah, provavelmente o feedback será um pouco mais lento, pois clonar o repositório é bem mais rápido que baixar uma imagem e rodar um container. Mas no final das contas, tomando cuidado com tags pra reutilizar imagens em cada passo, a diferença não será algo que vá causar dor de cabeça.

Você não *precisa* saber onde as coisas estão

O Rails te proporciona maneiras legais de acessar os diferentes ambientes a partir da sua própria máquina, basta definir uma variável de ambiente e as configurações apropriadas serão carregadas. Mas num projeto com arquitetura nativa na nuvem não é tão simples encontrar onde o servidor está rodando e, mesmo que encontre, não dá pra confiar que vai ficar lá por muito tempo.

O mundo de ops convergiu para a ideia de servidores efêmeros que são fáceis de subir, ao invés de servidores resilientes que não caem. Numa arquitetura de nuvem isso é levado ao extremo, os vendors (Amazon, Google etc) cuidam da distribuição de carga pra você e conseguem prover um nível mais alto de segurança, mas isso quer dizer que você fica com um pouco menos de controle (o que na verdade é bom!).

Lógico que é possível acessar um servidor, mas você precisa fazer isso utilizando as CLIs dos vendors (o que te dá mais segurança) e não pelo Rails. Pra consumir uma API por exemplo, utilizamos recursos de balanceamento de carga do Google Cloud Platform e ele iria levar a requisição para o servidor. E eu não precisava saber qual o IP do servidor em si, apenas do balanceador de carga.

O mesmo vale para o banco de dados, junto a imagem do servidor nós subíamos um proxy, do próprio Google Cloud, para conectar ao banco (que também é um recurso do Google Cloud). Na prática a aplicação Rails funcionava como se o banco estivesse rodando junto com ela, no localhost (mesmo em produção), e de novo eu não precisava saber aonde o banco estava.

Essa “falta de controle” na verdade quer dizer menos dor de cabeça pra você pois esses problemas já estarão resolvidos. Além disso os vendors provavelmente conseguem prover um nível de segurança bem mais alto, já que tem um time dedicado a isso.

Kubernetes é uma excelente ferramenta

Nesse projeto utilizamos o Google Kubernetes Engine do Google Cloud para gerenciar um cluster Kubernetes onde os containers Docker estariam rodando. O que eu mais curti do Kubernetes é que ele provê um balanço muito bom entre a quantidade de conhecimento de infra que eu preciso ter como um desenvolvedor.

Ter que fazer configurações usando yaml é bem ruim, mas não é um grande problema (e existem outras alternativas também) e no geral aprender Kubernetes foi uma boa experiência, existe muita documentação e a comunidade é bem ativa. Dá até pra rodar tudo localmente com o minikube.

Entender os conceitos básicos de Node, Pod etc do Kubernetes não é tão complexo e, uma vez que entra na sua cabeça, é bem fácil criar e configurar o cluster. Além disso as facilidades que o Kubernetes provê, desde rolling deploys até escalabilidade, tiram bastante preocupações da cabeça de quem desenvolve (e de quem mantém também).

Não é a toa que no último Radar de Tecnologia da ThoughtWorks apareceram tantos blips relacionados a Kubernetes e foi um dos temas do radar.

Bônus: Além dos microserviços

Utilizar o Kubernetes pra orquestrar containers facilitou bastante a nossa vida, mas ainda tinham problemas que precisavam ser resolvidos, por exemplo: todas as APIs estão expostas na internet, então temos que evitar uma série de problemas ao receber requisições.

Utilizamos duas soluções pra reduzir duplicações na plataforma como um todo: a primeira foi utilizar o Kong API Gateway pra facilitar a vida de quem quer consumir essas APIs e a segunda foi criar sidecars para lidar essas questões de segurança e facilitar a vida de quem desenvolve.

Além disso, a ideia de service mesh pra facilitar a comunicação entre os serviços da plataforma (sem contato com o mundo externo) também parece interessante, além de já existirem vários produtos no ecossistema Kubernetes.

3 Livros sobre Desenvolvimento Ágil

Se você trabalha com desenvolvimento de software e ouve falar em práticas ágeis como TDD, CI, Pareamento etc. aqui vão alguns livros que me ajudaram bastante a entender as ideias por trás do desenvolvimento ágil e acho que vai te ajudar a ter mais clareza na sua jornada.

The Agile Samurai

Esse livro só está disponível em inglês, mas ele é bem curto e a leitura é fácil. Se você está entrando em um time ágil ou faz parte de um time que está começando a adotar ágil, esse livro vai te ajudar a entender todo o processo de entrega de software, desde a ideação até a entrega em iterações.

Outra coisa legal é que ele aborda vários aspectos, não só a parte de desenvolvimento em si, então acaba sendo um livro útil pra vários papéis. O principal ponto pra ficar atento é que a ideia do livro é dar essa visão geral do desenvolvimento então vai ser necessário se aprofundar para de fato entender as motivações que geraram as práticas.

Extreme Programming Explained

Esse é um livro clássico do Kent Beck que fala sobre os fundamentos do XP e mostra os valores e princípios que estão na base das práticas comuns em times ágeis. A edição mais recente foi publicada em 2004, então algumas medidas (como a ideia de um build de 10 minutos) talvez não sejam tão reais.

Esse livro não vai te ensinar como fazer testes, TDD, pareamento, Integração Contínua etc, ele apenas apresenta esses conceitos e os define. O legal de verdade desse livro é entender o que motivou essas práticas e por que os times buscam utilizá-las no dia-a-dia. Esse também é um livro curtinho e fácil de ler.

The Art of Agile Development

Aqui temos um livro que é bem mais detalhado (longo) e legal pra quem quer aprofundar nas ideias do desenvolvimento ágil. O que me chamou muito a atenção nesse livro é que o autor não assume que você quer só aplicar as práticas e mostra como elas se conectam com os problemas da entrega de software.

Só pra ter uma ideia, a primeira parte do livro foca apenas em entender as motivações de adotar o desenvolvimento ágil e de saber o que funciona ou não. O livro também é baseado no XP e vai focar bastante no desenvolvimento de software, falando também dos valores, princípios e práticas.

Refatorando com confiança!

Você já encontrou algum código e pensou: “Nossa, que código bom!”? (obs: ler com voz irônica).

Talvez sim, mas provavelmente a proporção de base de códigos bom vs ruins é bem baixa. O que leva alguém a escrever um código ruim? Com certeza a habilidade e experiência da pessoa influencia na qualidade do seu código, meus primeiros códigos não tinham a mesma qualidade dos que escrevo hoje (ainda bem!).

Eu acredito que o principal fator que torna um código ruim não é a pessoa que escreveu, mas sim as várias pessoas que passaram por aquele código e não o melhoraram quando necessário (e já adianto que nem vou falar sobre a falta de tempo).

Qual o melhor momento para refatorar código?

Quando você precisa mudar um código para implementar uma nova funcionalidade. Não, não é durante o code review e nem fora das horas de trabalho.

Refatorar fora das horas de trabalho (horas que o time concorda em estar junto trabalhando) cria a cultura do heroísmo onde uma pessoa salva o projeto. O problema é que precisa de um herói para terminar o trabalho de outro herói, e ai já viu né.

Durante o code review é comum fazermos pequenas sugestões, alertar sobre código duplicado ou até conflitos de funcionalidade.

Durante a revisão de código quem está revisando provavelmente não sabe como aquele código vai precisar evoluir, então qualquer sugestão é baseada apenas na experiência da pessoa, é só um chute. Se aquela parte do código nunca mais for tocada, não importa se o código tá duplicado ou se a modelagem está bem feita, se os testes passam e o código funciona tá tudo bem.

Na hora de mudar vai tá tudo uma bagunça

Sim, provavelmente, e isso é bom! Na hora que precisar mudar você vai ter mais contexto de como o código precisa evoluir e qual seria um bom design, o que é bem melhor do que só um chute.

(Essa ideia de que revisão de código aumenta a qualidade do código é o que mais me incomoda na cultura de Pull Requests, mas essa polêmica fica pra outro post)

O que realmente causa a bagunça não é quem escreveu o código (a coitada da pessoa que escreveu não tinha como prever o futuro, certo?) é quem passa por ele e não se preocupa em melhorar.

Uma ideia interessante do livro 99 Bottles of OOP (um excelente livro da Sandi Metz e Katrina Owen, super recomendo) é o Shameless Green, que basicamente segue a ideia do TDD a risca. Escreva o código que faz os testes passarem e pronto.

Não adianta especular generalizações e nem forçar todas as abstrações de domínio possíveis. Apenas se preocupe em escrever o código que faz os testes passarem e confie que quando uma mudança for necessária, a pessoa que estiver escrevendo o código vai melhorá-lo.

Regras de negócio mudam, pessoas ganham mais conhecimento do negócio, da aplicação e de escrita de código em geral, é normal que o código precise de pequenas (ou grandes) melhorias de vez em quando.

Refatore com confiança!

Considerando que você tem mais contexto de quem escreveu o código original é hora de procurar por pontos de melhoria, e ai entram os code smells!

Eu já devo ter escrito por aqui outras vezes mas é sempre bom relembrar: identifique code smells primeiro refatore depois.

Um ponto importante sobre code smells é que eles não são estáticos (apesar de existirem ferramentas de análise estática de código que funcionam muito bem). Pense por um instante: qual é o real problema com o código duplicado?

Eu não acho que é ter duas (ou mais) partes parecidas de código fazendo a mesma coisa, mas sim alguma abstração do domínio que precisa ser identificada.

Aliar o contexto de negócio, sabendo como o código precisa evoluir, com o conhecimento de escrita de software é crucial.

Se você quiser conhecer mais sobre refatoração, padrões de projeto e design orientado a objetos colocando a mão na massa, dá uma olhada nos livros Refatorando com Padrões de Projeto (com versão em Ruby e Java).

Novo livro: Refatorando com Padrões de Projeto, um guia em Java!

Se você gosta de padrões de projeto e curte as publicações do blog, o livro Refatorando com Padrões de Projeto, um guia em Java é perfeito para você!

livro java

Sobre o livro

Se você já leu a série Mão na Massa sobre Padrões de Projeto aqui do blog, você vai curtir ler o livro. Segui a mesma ideia de ter exemplos práticos para utilização dos padrões, mas adicionei um pensamento mais crítico para a implementação através de técnicas de refatoração.

O conteúdo é o mesmo da edição em Ruby, mas adaptado ao contexto da linguagem Java, explorando as diferenças de linguagens estaticamente tipadas mas compartilhando as mesmas ideias: aplicar pequenas mudanças com visando alcançar um design melhor com Padrões de Projeto.

Público Alvo

Ter um entendimento bom de Orientação a Objetos é importante, mas muitas vezes é difícil encontrar exemplos práticos tanto de problemas quanto de boas soluções para o seu design.

Se você se encontra nesse meio termo, alguém que já passou pelo básico e está procurando um material mais prático, o livro vai te ajudar a entender o papel dos Padrões de Projeto no design e como Refatoração auxilia na hora de por a mão na massa!

Developer Experience

Já parou para pensar nas ferramentas que você, desenvolvedor, usa no dia-a-dia? Do editor de texto/IDE até como o software é implantado em produção, o que você utiliza precisam oferecer uma boa experiência, assim como um novo modelo de celular.

A evolução da Experiência de Uso (User eXperience – UX) nos proporciona maneiras cada vez melhores de interagir com nossos dispositivos, software e até nós mesmos. De maneira semelhante a evolução da Experiência de Desenvolvimento muda a maneira como o software é desenvolvido e como interagimos em equipe.

A revolução da Nuvem

Um grande benefício, poucas vezes reconhecido, de utilizar um serviço como Amazon ou Heroku é poder criá-las sem muita burocracia. Um git push e sua aplicação está rodando no Heroku, sem dependências com um time de infraestrutura.

De maneira semelhante, a popularização de contêineres com o Docker permite que você consiga rodar na sua máquina uns dois servidores Phoenix com um NGINX para balancear a carga, um Mongo para guardar dados, Memcached para fazer caching e um Nagios para monitorar tudo isso. Tá, talvez não tudo isso, mas dá pra endenter a ideia 🙂

O benefício de poder experimentar com tecnologias diferentes e colocá-las em produção sem muitas adaptações na infraestrutura aumenta muito a experiência de desenvolvimento.

O tempo para Hello World

O Hello World é a maneira mais fácil de experimentar uma ferramenta nova, não é nada complexo complexa e dá uma boa visão sobre como configurar um ambiente. O framework Rails ficou bem conhecido pela sua capacidade de permitir experimentação muito rápido, basta rodar alguns simples comandos e você tem uma estrutura completa, com views e banco de dados 100% funcionais.

Hoje em dia praticamente qualquer framework oferece alguma maneira de criar uma estrutura básica, com diretórios e configurações básicas. A linguagem Crystal (https://crystal-lang.org) já possui um comando que inicializa os diretórios, cria arquivos básicos, testes e inclusive configurações de um repositório Git – isso não é uma biblioteca, o executável da linguagem oferece isso!

Outro bom exemplo é o http://tryruby.org/ que permite aprender sobre a linguagem Ruby direto no navegador, sem instalar nada. Essa ideia levou o primeiro contato com a linguagem para outro nível de facilidade e hoje em dia várias linguagens/ferramentas possuem algo do tipo, como o tutorial de Go https://tour.golang.org/.

Esses são só alguns exemplos de como a preocupação em melhorar a vida dos desenvolvedores leva a criação de novas ferramentas que simplificam e facilitam seu uso. Nos próximos posts vamos explorar melhor o impacto dessas facilidades nos times de software, então acompanhe o blog e fique ligado 🙂

3 dicas para utilizar Padrões de Projeto

Aplicar um Padrão de Projeto pode ser um processo não muito simples, então siga essas dicas para ter mais confiança e entendimento antes de começar. Se quiser ir mais afundo no tema e entender como Padrões de Projeto podem ajudar, leia o livro Refatorando com Padrões de Projeto.

  1. Identifique a oportunidade de melhoria: Aplicar um Padrão de Projeto aumenta a complexidade do código, portanto é preciso ter certeza que vale a pena aplicá-lo. Comece pensando no que o código ganharia se o padrão for aplicado, pode ser tanto um code smell que será resolvido quanto uma alteração futura que será facilitada.
  2. Entenda o contexto do código: Cada Padrão de Projeto possui um contexto onde ele faz sentido e de fato resolve o problema, apesar de aumentar a complexidade. Aplicar um padrão fora de contexto vai causar tanto dificultar sua implementação quanto dificultar o entendimento dos outros. O coitado do Builder que o diga.
  3. Aplique pequenas mudanças nos testes e no código: No post anterior falei sobre a diferença entre refatorar e mudar o código, se quiser aplicar um padrão refatore! Essas mudanças em pequenos passos, além de te dar mais segurança, também servem para te dar um entendimento melhor do design que você está propondo. Pode ser que no meio da refatoração você descubra que apenas modificar um pouco o design resolve o problema, sem adicionar toda a complexidade dos padrões.

Lembre-se sempre que Padrões de Projeto adicionam complexidade ao código, então é preciso entender se vale a pena aplicá-los ou não. Se decidir por aplicá-los, siga sempre refatorando o código, evite fazer grandes mudanças no código de qualquer jeito, seja um profissional disciplinado!