desenvolvimento de aplicações para o
Google App Engine




               http://slideshare.net/chesterbr
Proposta

  Apresentar de forma simples,
prática e ao alcance de todos uma
   alternativa para a criação de
  aplicativos na web escaláveis.


              http://slideshare.net/chesterbr
Palestrante




                   @chesterbr
              http://chester.me
não-especialista




(ou seja: se esse mané pode, eu também posso!)
Como surgem os bons
  aplicativos web?
existem muitas lendas...
A mais popular
Dilema da Hospedagem
   Enquanto o site não fizer sucesso,
   vou ter que custear a hospedagem

Quando ele crescer e meu provedor não
aguentar, vou ter que mudar de provedor
         (e talvez de tecnologia)

        Quanto isso vai custar?
Dilema da Arquitetura

  Projetar uma arquitetura para escalar
 exige tempo e skills, que poderiam ser
    aplicados na aplicação em si (em
particular no início), mas deixar isso pra
 depois pode gerar um problema difícil
Google App Engine
Equilíbrio

Crie seu aplicativo web rapidamente e
a custo zero. Com alguns cuidados, ele
  vai se adaptar a volumes de tráfego
maiores e o custo de hospedagem será
     proporcional a este aumento.
Obstáculos

 O App Engine não é completamente
diferente de outras arquiteturas, mas é
     preciso aprender coisas novas

   Nossa proposta hoje é ver essas
       coisas novas na prática
Escolhendo a Linguagem
?
Java

É uma opção para quem já conhece ela
 (ou C#), mas muita coisa vai ter que
    ser feita do “jeito App Engine”

(e não é lá muito popular hoje em dia...)
Java




X
Go
 Criada pelo próprio Google, é boa em
   tarefas que exigem muita CPU (é
compilada e com tipos estáticos), mas o
 suporte ainda é experimental* e você
        vai ter pouca companhia


    * eles mesmos alertam: http://code.google.com/appengine/docs/
Go
Python
     Fácil de aprender, poderosa
   (dinâmica, funcional, interativa),
estimula a escrita de código legível e
 tem uma comunidade muito ativa*



                  *
Python
Hello, App Engine
Ingredientes

● Google App Engine SDK para Python
● Seu editor de textos favorito

● Internet (para colocar no ar)



    (opcional: Eclipse + plugin do App Engine)



                 http://code.google.com/appengine/downloads.html
SDK (Launcher) no Windows




         http://code.google.com/appengine/downloads.html
SDK (Launcher) no Mac




       http://code.google.com/appengine/downloads.html
Um app é uma pasta
Um app é uma pasta
app.yaml

  Descreve o seu aplicativo para os
servidores do Google (nome, versão,
linguagem), associando os endereços
  (ex.: “/”, “/noticias”) com o código
app.yaml
application: meusite
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: meusite.py
meusite.py
print "Oi, Campus Party!"
Tá pronto, vamos rodar!
acrescentando no Launcher
diga onde ele está...
...e solta o play!
era só isso?
Era!




☺
Falando sério agora...
Criando via Launcher
Criando via Launcher
app.yaml
application: siteserio
version: 1
runtime: python
api_version: 1

Handlers:
- url: /favicon.ico
  static_files: favicon.ico
  upload: favicon.ico

- url: .*
  script: main.py
main.py “sério”
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util

class MainHandler(webapp.RequestHandler):
    def get(self):
        self.response.out.write('Hello world!')

def main():
    application = webapp.WSGIApplication(
        [('/', MainHandler)],
          debug=True)
    util.run_wsgi_app(application)

if __name__ == '__main__':
    main()
webapp

 É a biblioteca (framework) que mapeia
(através de um objeto WSGIApplication)
 cada caminho (ou grupo deles) para a
    classe RequestHandler apropriada
Exemplo: site de notícias
...

def main():
    application = webapp.WSGIApplication([
           ('/', HomeHandler),
           ('/noticias', ListaNoticiasHandler),
           ('/noticia/(w+)', NoticiaHandler),
           ...
        ], debug=True)
    util.run_wsgi_app(application)

...
Recuperando a notícia
...
class NoticiaHandler(webapp.RequestHandler):
    def get(self, id_not):
        # id_not contém o item entre
        # parênteses em '/noticia/(w+)'
        # ex.: /noticia/123 => id_not=123
        noticia = dao.busca_noticia(id_not)

        # montando o html com os dados:
        html = template.render('/noticia.html',
                               noticia)
        self.response.out.write(noticia)
...
Template (noticia.html)
<html>
  <body>
    <h1>{{titulo}}</h1>
    <h2>{{autor.nickname}}</h2>
    {{texto}}
  </body>
</html>
Parâmetros e REST
...
class AlgumHandler(webapp.RequestHandler):
    def get(self):
        # parâmetros de formulário (GET, POST):
        p = self.request.get('nome_parametro')

      # Outros verbos HTTP (i.e., REST):
      def post(self):
          ...
      def delete(self):
          ...

...
Alternativas
O webapp é minimalista, mas se isso
 não agradar, o App Engine suporta
   outros frameworks populares




            http://www.franciscosouza.com.br/tag/frameworks/
Armazenando Dados
Jeito clássico (relacional)
Bancos Relacionais

Têm implementações maduras, facilitam
 operações robustas (ACID), mapeiam
 (mais-ou-menos) com classes/objetos,
 performam bem em servidor único e
  (quase) todo mundo sabe usar SQL

               mas...
Bancos Relacionais

  ...é difícil paralelizar sem afetar o
aplicativo e/ou abrir mão de algumas
dessas vantagens, o que tem levado à
      busca de novas alternativas
App Engine Datastore
Baseada no Bigtable, que é

“Um mapa ordenado esparso, distribuído,
persistente e multidimensional. O mapa é
  indexado por chave de linha, chave de
coluna e data/hora; cada valor no mapa é
   um array não-interpretado de bytes”


             http://research.google.com/archive/bigtable-osdi06.pdf
Na prática

Vamos usar uma estrutura mais simples,
 na qual o aplicativo vai cuidar de mais
coisas (ex.: consistência de dados), mas
  o sistema poderá escalar facilmente
     usando a estrutura do Google
Boa notícia

O App Engine reduz esse trabalho com
classes que encapsulam o Datastore na
 forma de “entidades” e permitem até
    consultar em estilo SQL (GQL)

     (só tome cuidado com as diferenças)
Exemplo
...
class Noticia(db.Model):
    id = db.IntegerProperty(required=True)
    titulo = db.StringProperty(required=True)
    texto = db.StringProperty(required=True)
    editoria = db.StringProperty(required=True,
         choices=set(['politica', 'esportes',
                      'informatica']))
    data_criacao = db.DateTimeProperty(
                       auto_now=True)
    data_publicacao = db.DateTimeProperty()
    autor = db.UserProperty()
    avaliacao = db.IntegerProperty()
    acessos = db.IntegerProperty()
...
Cadastrando (put)
...
      noticia = Noticia(
                    id = 123,
                    titulo = 'SOPA foi pro vinagre!',
                    texto = 'bla bla bla bla',
                    editoria = 'politica')
      noticia.put()
...
Consulta (query)
...
      # Montando a query
      q = Noticia.all()
      q.filter("editoria =", "esportes")
      q.order("-data_publicacao")


      # Executando a query
      noticias = q.fetch(10)
      for noticia in noticias:
          print noticia.titulo
...
Consulta (query) com GQL
...
      # Montando a query
      q = db.GqlQuery("SELECT * FROM Noticia " +
                      "WHERE editoria = :1" +
                      "ORDER BY data_publicacao DESC",
                      "esportes")

      # Executando a query (não mudou nada!)
      noticias = q.fetch(10)
      for noticia in noticias:
          print noticia.titulo
...
Índices

  Todas as consultas são baseadas em
 índices definidos no index.yaml (mas
criados automaticamente à medida que
  você testa o site no servidor local)

     (sim, vale dar uma espiada no arquivo)
Restrições

Como as buscas usam índices, existem
   algumas restrições. Por exemplo,
desigualdades (<, <=, >=, >, !=) só podem
    afetar um campo por consulta.



                 http://bit.ly/y3xtkk (Documentação: Restrições)
Restrições
...
      # Query válida
      q = Noticia.all()
      q.filter("avaliacao >=", 3)
      q.filter("avaliacao <=", 8)
...
      # Query INVÁLIDA
      q = Noticia.all()
      q.filter("avaliacao >=", 5)
      q.filter("acessos >=", 12)
...




                        http://bit.ly/y3xtkk (Documentação: Restrições)
Memcache

Alguns dados são muito mais acessados
que outros (working set), e o AppEngine
 disponbiliza o Memcache para manter
         esses dados em RAM
Memcache
  ...
  def busca_noticia(self, id):
      cache = memcache.Client()
      noticia = cache.get(id)
      if noticia is None:
          result = Noticia.all().filter("id =",
                     int(id)).fetch(1)
          if result:
              noticia = result[0]
              cache.add(id, noticia)
      return noticia
  ...




(não esqueça do cache.delete() se os dados mudarem)
Colocando no ar
appengine.google.com
Cadastrando o aplicativo
oh, oh...
cadastre com outro nome...
...e altere no app.yaml
application: appdojoselito
version: 1
runtime: python
api_version: 1

Handlers:
- url: /favicon.ico
  static_files: favicon.ico
  upload: favicon.ico

- url: .*
  script: main.py
Launcher
login do Google
ele trabalha, e...
Conclusão
O poder é de vocês!

  É preciso estudar e experimentar, mas
  o App Engine está ao alcance de todos.
             Basta começar!




http://code.google.com/intl/pt-BR/appengine/docs/
Dúvidas?
Obrigado!

                      @chesterbr
                 http://chester.me
   http://slideshare.net/chesterbr
Créditos e Licenciamento
          Esta apresentação está disponível para uso e reuso
       sob os termos da licença Creative Commons “by-nc” 3.0,
                    observadas as exceções abaixo




   Fotos e ilustrações são em sua maioria logomarcas dos produtos e
projetos referenciados (inclusos sob premissa de “fair use”) e ilustrações
   de uso supostamente livre cuja autoria foi mencionada sempre que
possível (correções são bem-vindas). Tais elementos são de propriedade
 de seus autores, e não estão cobertos pela licença acima, não havendo
                   qualquer relação deles com o autor

Desenvolvimento de Aplicações para o Google App Engine (CPBR5)

  • 1.
    desenvolvimento de aplicaçõespara o Google App Engine http://slideshare.net/chesterbr
  • 2.
    Proposta Apresentarde forma simples, prática e ao alcance de todos uma alternativa para a criação de aplicativos na web escaláveis. http://slideshare.net/chesterbr
  • 3.
    Palestrante @chesterbr http://chester.me
  • 4.
    não-especialista (ou seja: seesse mané pode, eu também posso!)
  • 5.
    Como surgem osbons aplicativos web?
  • 6.
  • 7.
  • 8.
    Dilema da Hospedagem Enquanto o site não fizer sucesso, vou ter que custear a hospedagem Quando ele crescer e meu provedor não aguentar, vou ter que mudar de provedor (e talvez de tecnologia) Quanto isso vai custar?
  • 9.
    Dilema da Arquitetura Projetar uma arquitetura para escalar exige tempo e skills, que poderiam ser aplicados na aplicação em si (em particular no início), mas deixar isso pra depois pode gerar um problema difícil
  • 10.
  • 11.
    Equilíbrio Crie seu aplicativoweb rapidamente e a custo zero. Com alguns cuidados, ele vai se adaptar a volumes de tráfego maiores e o custo de hospedagem será proporcional a este aumento.
  • 12.
    Obstáculos O AppEngine não é completamente diferente de outras arquiteturas, mas é preciso aprender coisas novas Nossa proposta hoje é ver essas coisas novas na prática
  • 13.
  • 14.
  • 15.
    Java É uma opçãopara quem já conhece ela (ou C#), mas muita coisa vai ter que ser feita do “jeito App Engine” (e não é lá muito popular hoje em dia...)
  • 16.
  • 17.
    Go Criada pelopróprio Google, é boa em tarefas que exigem muita CPU (é compilada e com tipos estáticos), mas o suporte ainda é experimental* e você vai ter pouca companhia * eles mesmos alertam: http://code.google.com/appengine/docs/
  • 18.
  • 19.
    Python Fácil de aprender, poderosa (dinâmica, funcional, interativa), estimula a escrita de código legível e tem uma comunidade muito ativa* *
  • 20.
  • 21.
  • 22.
    Ingredientes ● Google AppEngine SDK para Python ● Seu editor de textos favorito ● Internet (para colocar no ar) (opcional: Eclipse + plugin do App Engine) http://code.google.com/appengine/downloads.html
  • 23.
    SDK (Launcher) noWindows http://code.google.com/appengine/downloads.html
  • 24.
    SDK (Launcher) noMac http://code.google.com/appengine/downloads.html
  • 26.
    Um app éuma pasta
  • 27.
    Um app éuma pasta
  • 28.
    app.yaml Descreveo seu aplicativo para os servidores do Google (nome, versão, linguagem), associando os endereços (ex.: “/”, “/noticias”) com o código
  • 29.
    app.yaml application: meusite version: 1 runtime:python api_version: 1 handlers: - url: /.* script: meusite.py
  • 31.
  • 33.
  • 34.
  • 35.
    diga onde eleestá...
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 44.
    app.yaml application: siteserio version: 1 runtime:python api_version: 1 Handlers: - url: /favicon.ico static_files: favicon.ico upload: favicon.ico - url: .* script: main.py
  • 45.
    main.py “sério” from google.appengine.extimport webapp from google.appengine.ext.webapp import util class MainHandler(webapp.RequestHandler): def get(self): self.response.out.write('Hello world!') def main(): application = webapp.WSGIApplication( [('/', MainHandler)], debug=True) util.run_wsgi_app(application) if __name__ == '__main__': main()
  • 46.
    webapp É abiblioteca (framework) que mapeia (através de um objeto WSGIApplication) cada caminho (ou grupo deles) para a classe RequestHandler apropriada
  • 47.
    Exemplo: site denotícias ... def main(): application = webapp.WSGIApplication([ ('/', HomeHandler), ('/noticias', ListaNoticiasHandler), ('/noticia/(w+)', NoticiaHandler), ... ], debug=True) util.run_wsgi_app(application) ...
  • 48.
    Recuperando a notícia ... classNoticiaHandler(webapp.RequestHandler): def get(self, id_not): # id_not contém o item entre # parênteses em '/noticia/(w+)' # ex.: /noticia/123 => id_not=123 noticia = dao.busca_noticia(id_not) # montando o html com os dados: html = template.render('/noticia.html', noticia) self.response.out.write(noticia) ...
  • 49.
    Template (noticia.html) <html> <body> <h1>{{titulo}}</h1> <h2>{{autor.nickname}}</h2> {{texto}} </body> </html>
  • 50.
    Parâmetros e REST ... classAlgumHandler(webapp.RequestHandler): def get(self): # parâmetros de formulário (GET, POST): p = self.request.get('nome_parametro') # Outros verbos HTTP (i.e., REST): def post(self): ... def delete(self): ... ...
  • 51.
    Alternativas O webapp éminimalista, mas se isso não agradar, o App Engine suporta outros frameworks populares http://www.franciscosouza.com.br/tag/frameworks/
  • 52.
  • 53.
  • 54.
    Bancos Relacionais Têm implementaçõesmaduras, facilitam operações robustas (ACID), mapeiam (mais-ou-menos) com classes/objetos, performam bem em servidor único e (quase) todo mundo sabe usar SQL mas...
  • 55.
    Bancos Relacionais ...é difícil paralelizar sem afetar o aplicativo e/ou abrir mão de algumas dessas vantagens, o que tem levado à busca de novas alternativas
  • 56.
  • 57.
    Baseada no Bigtable,que é “Um mapa ordenado esparso, distribuído, persistente e multidimensional. O mapa é indexado por chave de linha, chave de coluna e data/hora; cada valor no mapa é um array não-interpretado de bytes” http://research.google.com/archive/bigtable-osdi06.pdf
  • 58.
    Na prática Vamos usaruma estrutura mais simples, na qual o aplicativo vai cuidar de mais coisas (ex.: consistência de dados), mas o sistema poderá escalar facilmente usando a estrutura do Google
  • 59.
    Boa notícia O AppEngine reduz esse trabalho com classes que encapsulam o Datastore na forma de “entidades” e permitem até consultar em estilo SQL (GQL) (só tome cuidado com as diferenças)
  • 60.
    Exemplo ... class Noticia(db.Model): id = db.IntegerProperty(required=True) titulo = db.StringProperty(required=True) texto = db.StringProperty(required=True) editoria = db.StringProperty(required=True, choices=set(['politica', 'esportes', 'informatica'])) data_criacao = db.DateTimeProperty( auto_now=True) data_publicacao = db.DateTimeProperty() autor = db.UserProperty() avaliacao = db.IntegerProperty() acessos = db.IntegerProperty() ...
  • 61.
    Cadastrando (put) ... noticia = Noticia( id = 123, titulo = 'SOPA foi pro vinagre!', texto = 'bla bla bla bla', editoria = 'politica') noticia.put() ...
  • 62.
    Consulta (query) ... # Montando a query q = Noticia.all() q.filter("editoria =", "esportes") q.order("-data_publicacao") # Executando a query noticias = q.fetch(10) for noticia in noticias: print noticia.titulo ...
  • 63.
    Consulta (query) comGQL ... # Montando a query q = db.GqlQuery("SELECT * FROM Noticia " + "WHERE editoria = :1" + "ORDER BY data_publicacao DESC", "esportes") # Executando a query (não mudou nada!) noticias = q.fetch(10) for noticia in noticias: print noticia.titulo ...
  • 64.
    Índices Todasas consultas são baseadas em índices definidos no index.yaml (mas criados automaticamente à medida que você testa o site no servidor local) (sim, vale dar uma espiada no arquivo)
  • 65.
    Restrições Como as buscasusam índices, existem algumas restrições. Por exemplo, desigualdades (<, <=, >=, >, !=) só podem afetar um campo por consulta. http://bit.ly/y3xtkk (Documentação: Restrições)
  • 66.
    Restrições ... # Query válida q = Noticia.all() q.filter("avaliacao >=", 3) q.filter("avaliacao <=", 8) ... # Query INVÁLIDA q = Noticia.all() q.filter("avaliacao >=", 5) q.filter("acessos >=", 12) ... http://bit.ly/y3xtkk (Documentação: Restrições)
  • 67.
    Memcache Alguns dados sãomuito mais acessados que outros (working set), e o AppEngine disponbiliza o Memcache para manter esses dados em RAM
  • 68.
    Memcache ... def busca_noticia(self, id): cache = memcache.Client() noticia = cache.get(id) if noticia is None: result = Noticia.all().filter("id =", int(id)).fetch(1) if result: noticia = result[0] cache.add(id, noticia) return noticia ... (não esqueça do cache.delete() se os dados mudarem)
  • 69.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
    ...e altere noapp.yaml application: appdojoselito version: 1 runtime: python api_version: 1 Handlers: - url: /favicon.ico static_files: favicon.ico upload: favicon.ico - url: .* script: main.py
  • 76.
  • 77.
  • 78.
  • 81.
  • 82.
    O poder éde vocês! É preciso estudar e experimentar, mas o App Engine está ao alcance de todos. Basta começar! http://code.google.com/intl/pt-BR/appengine/docs/
  • 83.
    Dúvidas? Obrigado! @chesterbr http://chester.me http://slideshare.net/chesterbr
  • 84.
    Créditos e Licenciamento Esta apresentação está disponível para uso e reuso sob os termos da licença Creative Commons “by-nc” 3.0, observadas as exceções abaixo Fotos e ilustrações são em sua maioria logomarcas dos produtos e projetos referenciados (inclusos sob premissa de “fair use”) e ilustrações de uso supostamente livre cuja autoria foi mencionada sempre que possível (correções são bem-vindas). Tais elementos são de propriedade de seus autores, e não estão cobertos pela licença acima, não havendo qualquer relação deles com o autor