Três anos de Scala no
NewsMonitor
Felipe Hummel
• Site profissional para monitoramento de notícias em
tempo real
• 170M de notícias
• 5M/mês
• 2 Devs Backend + 3 Devs PHP/...
Como escolhemos Scala
• busk.com
• Fechado e pivotado
para o NewsMonitor
• Decisão de reaproveitar
código legado em Ruby
o...
Elastic
Search
Elastic
Search
Crawlers
Arquitetura Geral
Stark Indexer
MySQLMySQL Redis
Search API
Elastic
Search
autocomp...
Arquitetura
Coleta de Notícias
SocialCrawler
Feed
Crawler
Article
Crawler
Site
Crawler
Fila de Coleta
Article
Crawler
Arti...
Scala
Scala
é muito boa como dizem
Scala, por quê?
• Concisão de código sem perca de legibilidade
• Inferência de tipos
• Sintaxe extremamente sucinta para f...
Scala, por quê?
val idsDeAlunos = List(1423, 23245, 5343)

val cursosPorNome =

Map("Computação" -> 1234,

"Matemática" ->...
Scala, por quê?
val idsDeAlunos = List(1423, 23245, 5343)

val cursosPorNome =

Map("Computação" -> 1234,

"Matemática" ->...
Scala, por quê?
val idsDeAlunos = List(1423, 23245, 5343)

val cursosPorNome =

Map("Computação" -> 1234,

"Matemática" ->...
Scala, por quê?
val idsDeAlunos = List(1423, 23245, 5343)

val cursosPorNome =

Map("Computação" -> 1234,

"Matemática" ->...
Scala, por quê?
val idsDeAlunos = List(1423, 23245, 5343)

val cursosPorNome =

Map("Computação" -> 1234,

"Matemática" ->...
Scala, por quê?
case class Aluno(id: Int, curso: Curso, idade: Int)



val alunosPorIdade =

idsDeAlunos.map( id => carreg...
Scala, por quê?
case class Aluno(id: Int, curso: Curso, idade: Int)



val alunosPorIdade =

idsDeAlunos.map( id => carreg...
Scala, por quê?
case class Aluno(id: Int, curso: Curso, idade: Int)



val alunosPorIdade =

idsDeAlunos.map( id => carreg...
Scala, por quê?
case class Aluno(id: Int, curso: Curso, idade: Int)



val alunosPorIdade =

idsDeAlunos.map( id => carreg...
Scala, por quê?
case class Aluno(id: Int, curso: Curso, idade: Int)



val alunosPorIdade: Map[Int, List[Aluno]] =

idsDeA...
Scala, por quê?
case class Aluno(id: Int, curso: Curso, idade: Int)



val alunosPorIdade: Map[Int, List[Aluno]] =

idsDeA...
Scala, por quê?
• Várias pequenas funcionalidades que ajudam muito no
dia a dia
• Default e named parameters
• case classe...
Scala é isso
80% de Scala é isso
Scala
pode ser complicada como dizem
__ _ _ _ Placeholder __ __ _ _
val lista = List(“maria”, “José”, “joão”, “Carlos")



lista.map( n => n.toUpperCase ) // L...
__ _ _ _ Placeholder __ __ _ _
val lista = List(“maria”, “José”, “joão”, “Carlos")



lista.map( n => n.toUpperCase ) // L...
__ _ _ _ Placeholder __ __ _ _
val lista = List(“maria”, “José”, “joão”, “Carlos")



lista.map( n => n.toUpperCase ) // L...
Implicits conversions






10.seconds // Int não tem o método seconds

^~~~~~ erro de compilação

Implicits conversions


import scala.concurrent.duration.DurationInt



10.seconds // Int agora “tem" o método seconds
Implicits conversions






import scala.concurrent.duration.DurationInt



val time: Duration = 10.seconds





import org.scalatest.Matchers._
val resultado: String = …

resultado should equal ("42")

Implicits conversions
import w...
implicit conversions
• Conceito similar ao que dá pra fazer em Ruby ou
Javascript, estendendo classes mas com tipagem
está...
Interoperabilidade com Java
• Em geral funciona bem
• Mas alguns conceitos de Java e Scala são
irreconciliáveis
• Na práti...
Scala
é complicada como dizem
Scala
é complicada como dizem
em poucas coisas
Compilador
• Poderoso mas “lento”
• Pra quem vem de Java, Go e linguagens
dinâmicas
• Rápido pra quem vem de C++
• Na prát...
Estilos de Scala
• Muitas formas de escrever o mesmo código
• Um mais cool, outro mais funcional, outro mais
imperativo
• ...
Estilos de Scala
val lista = List(0, 1, 2, 3, 4)



lista.map( n => n + 1 )



Estilos de Scala
val lista = List(0, 1, 2, 3, 4)



lista.map { n => n + 1 }



Estilos de Scala
val lista = List(0, 1, 2, 3, 4)



lista map { n => n + 1 }



Estilos de Scala
val lista = List(0, 1, 2, 3, 4)



lista.map { _ + 1 }



Estilos de Scala
val lista = List(0, 1, 2, 3, 4)



lista.map ( _ + 1 )



Estilos de Scala




val lista = List(0, 1, 2, 3, 4)



def add1(n: Int) = n + 1



lista.map (add1)



Estilos de Scala




val lista = List(0, 1, 2, 3, 4)



def add1(n: Int) = n + 1



lista map add1



Estilos de Scala
lista.map ( n => n + 1 ) <—- Usamos

lista.map { n => n + 1 } <—- Usamos

lista map { n => n + 1 }

lista...
Uso de memória e
tempo de startup
• Estar na JVM tem vantagens e desvantagens
• Uso de memória
• Scala piora um pouquinho ...
Scala Avançado e
Curva de Aprendizado
• Algumas partes da comunidade enveredam demais pelo caminho funcional
• Você não é ...
Scala
mudou a forma
como programamos
Parar de acessar
o que não está lá
• NullPointerException (Java)
• undefined is not a function (Javascript)
• AttributeErr...
Parar de acessar
o que não está lá
• NullPointerException (Java)
• undefined is not a function (Javascript)
• AttributeErr...
Null Pointer Exc… NÃO
• NullPointerException (Java)
• undefined is not a function (Javascript)
• AttributeError: 'NoneType...
Null Pointer Exc… NÃO
• Uso de Option[MeuTipo] quando necessário
Tipagem Estática!
• Linguagens com tipagem estáticas pegaram fama de serem
verbosas
• Não necessariamente
• Scala consegue...
Imutabilidade
• Coisas a menos pra guardar na sua cabeça
• Não me preocupo se alguém pode ou vai mudar meu objeto
• Você p...
public class Person {

private final String firstName;

private final String lastName;
String getFirstName() { return firs...
case class Person(firstName: String, lastName: String)
imutável é a palavra
Scala é a melhor coisa do
mundo?
Scala é a melhor coisa do
mundo?
$escapedName = mysql_escape_string($u)

$escapedCurso = mysql_real_escape_string($c)

$sql =

“SELECT * FROM usuarios

WHE...
A minha
linguagem/framework/biblioteca
não é a melhor possível
Mais conciso e expressivo
que Scala é impossível
Mais conciso e expressivo
que Haskell é impossível
Programação é sempre um
comando seguido do outro
Programação pode ser só
(funções (chamando (funções ‘!’)))
em Clojure
Programar interfaces é ter que lidar
com estado mutável o tempo todo
Programar interfaces é isolar o
estado mutável com ReactJS
Ou damos free() na mão
ou usamos Garbage Collector
Ou damos free() na mão
ou usamos Garbage Collector
ou usamos Rust
e o seu sistema de ownership
Sempre dá pra melhorar
Obrigado!
Dúvidas?
@felipehummel
felipe.hummel@newsmonitor.com.br
Akka
Akka :)
• Simplifica muito o modelo mental para trabalhar com concorrência
• Cria "bolhas" onde você pode ser mutável à von...
Akka :(
• Toma conta do código (framework)
• A relação entre actors não é tão óbvia no código quanto a relação entre objet...
Três anos de Scala no NewsMonitor
Três anos de Scala no NewsMonitor
Três anos de Scala no NewsMonitor
Três anos de Scala no NewsMonitor
Três anos de Scala no NewsMonitor
Próximos SlideShares
Carregando em…5
×

Três anos de Scala no NewsMonitor

347 visualizações

Publicada em

Nesta palestra, veremos como o NewsMonitor, uma ferramenta de monitoração de notícias e clipping digital, começou a usar Scala em 2012. Desde então, temos usado a linguagem como diferencial técnico. A linguagem permitiu que uma pequena equipe criasse uma grande base de código em pouco tempo, mantendo o custo de infraestrutura baixo. Foram desenvolvidos desde sistemas de recomendação até um avançado coletor de notícias em tempo real.

Serão discutidos os pontos positivos da escolha da linguagem Scala, especialmente as funcionalidades que fizeram diferença no desenvolvimento: case classes, imutabilidade, implícitos e biblioteca de coleções. Além disso, serão mostrados os desafios enfrentados pelo grupo: falta de padrões de estilo, complexidade de código, "fanatismo funcional" e perda de performance.

Por fim, veremos a arquitetura que foi implementada no back-end do NewsMonitor, em especial como é organizado o coletor distribuído de notícias.

Publicada em: Tecnologia
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
347
No SlideShare
0
A partir de incorporações
0
Número de incorporações
13
Ações
Compartilhamentos
0
Downloads
4
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Três anos de Scala no NewsMonitor

  1. 1. Três anos de Scala no NewsMonitor Felipe Hummel
  2. 2. • Site profissional para monitoramento de notícias em tempo real • 170M de notícias • 5M/mês • 2 Devs Backend + 3 Devs PHP/Frontend • ~30K linhas de código Scala
  3. 3. Como escolhemos Scala • busk.com • Fechado e pivotado para o NewsMonitor • Decisão de reaproveitar código legado em Ruby ou criar novo • Aplicação ficou em PHP • Backend em Scala
  4. 4. Elastic Search Elastic Search Crawlers Arquitetura Geral Stark Indexer MySQLMySQL Redis Search API Elastic Search autocomplete
  5. 5. Arquitetura Coleta de Notícias SocialCrawler Feed Crawler Article Crawler Site Crawler Fila de Coleta Article Crawler Article Crawler … Article Crawler SeedCrawler SeedCrawler SeedCrawler
  6. 6. Scala
  7. 7. Scala é muito boa como dizem
  8. 8. Scala, por quê? • Concisão de código sem perca de legibilidade • Inferência de tipos • Sintaxe extremamente sucinta para funções anônimas • Coleções: List, Array, Map, Seq, Set, String • map, filter, groupBy, sortBy, distinct • Quase tudo faz parte da biblioteca e não é sintaxe especial da linguagem
  9. 9. Scala, por quê? val idsDeAlunos = List(1423, 23245, 5343)
 val cursosPorNome =
 Map("Computação" -> 1234,
 "Matemática" -> 423,
 "Física" -> 5322,
 "Biologia" -> 1312)
  10. 10. Scala, por quê? val idsDeAlunos = List(1423, 23245, 5343)
 val cursosPorNome =
 Map("Computação" -> 1234,
 "Matemática" -> 423,
 "Física" -> 5322,
 "Biologia" -> 1312) Inferência de tipos
  11. 11. Scala, por quê? val idsDeAlunos = List(1423, 23245, 5343)
 val cursosPorNome =
 Map("Computação" -> 1234,
 "Matemática" -> 423,
 "Física" -> 5322,
 "Biologia" -> 1312) Inferência de tipos
  12. 12. Scala, por quê? val idsDeAlunos = List(1423, 23245, 5343)
 val cursosPorNome =
 Map("Computação" -> 1234,
 "Matemática" -> 423,
 "Física" -> 5322,
 "Biologia" -> 1312) Não é sintaxe especial
  13. 13. Scala, por quê? val idsDeAlunos = List(1423, 23245, 5343)
 val cursosPorNome =
 Map("Computação" -> 1234,
 "Matemática" -> 423,
 "Física" -> 5322,
 "Biologia" -> 1312)
  14. 14. Scala, por quê? case class Aluno(id: Int, curso: Curso, idade: Int)
 
 val alunosPorIdade =
 idsDeAlunos.map( id => carregaAluno(id) )
 
 

  15. 15. Scala, por quê? case class Aluno(id: Int, curso: Curso, idade: Int)
 
 val alunosPorIdade =
 idsDeAlunos.map( id => carregaAluno(id) )
 .filter(_.curso.nome == "Computação")
 

  16. 16. Scala, por quê? case class Aluno(id: Int, curso: Curso, idade: Int)
 
 val alunosPorIdade =
 idsDeAlunos.map( id => carregaAluno(id) )
 .filter(_.curso.nome == "Computação")
 .filter(_.idade > 18)

  17. 17. Scala, por quê? case class Aluno(id: Int, curso: Curso, idade: Int)
 
 val alunosPorIdade =
 idsDeAlunos.map( id => carregaAluno(id) )
 .filter(_.curso.nome == "Computação")
 .filter(_.idade > 18)
 .groupBy(_.idade)
  18. 18. Scala, por quê? case class Aluno(id: Int, curso: Curso, idade: Int)
 
 val alunosPorIdade: Map[Int, List[Aluno]] =
 idsDeAlunos.map( id => carregaAluno(id) )
 .filter(_.curso.nome == "Computação")
 .filter(_.idade > 18)
 .groupBy(_.idade)
  19. 19. Scala, por quê? case class Aluno(id: Int, curso: Curso, idade: Int)
 
 val alunosPorIdade: Map[Int, List[Aluno]] =
 idsDeAlunos.map( id => carregaAluno(id) )
 .filter(_.curso.nome == "Computação")
 .filter(_.idade > 18)
 .groupBy(_.idade) funções anônimas sucintas
  20. 20. Scala, por quê? • Várias pequenas funcionalidades que ajudam muito no dia a dia • Default e named parameters • case classes: syntactic sugar que vale a pena • Pattern Matching: switch case+++ • Preferência por imutabilidade mas sempre dando opção por mutabilidade (quando necessária)
  21. 21. Scala é isso
  22. 22. 80% de Scala é isso
  23. 23. Scala pode ser complicada como dizem
  24. 24. __ _ _ _ Placeholder __ __ _ _ val lista = List(“maria”, “José”, “joão”, “Carlos")
 
 lista.map( n => n.toUpperCase ) // List(“MARIA”, …)
 lista.map( _.toUpperCase ) // List(“MARIA”, …)
 
 

  25. 25. __ _ _ _ Placeholder __ __ _ _ val lista = List(“maria”, “José”, “joão”, “Carlos")
 
 lista.map( n => n.toUpperCase ) // List(“MARIA”, …)
 lista.map( _.toUpperCase ) // List(“MARIA”, …)
 
 lista.map( _.map(_.toUpper)) // List(“MARIA”, …)

  26. 26. __ _ _ _ Placeholder __ __ _ _ val lista = List(“maria”, “José”, “joão”, “Carlos")
 
 lista.map( n => n.toUpperCase ) // List(“MARIA”, …)
 lista.map( _.toUpperCase ) // List(“MARIA”, …)
 
 lista.map( _.map(_.toUpper)) // List(“MARIA”, …)
 lista.map { str =>
 str.map( c => c.toUpper)
 } // List(“MARIA”, …)
  27. 27. Implicits conversions 
 
 
 10.seconds // Int não tem o método seconds
 ^~~~~~ erro de compilação

  28. 28. Implicits conversions 
 import scala.concurrent.duration.DurationInt
 
 10.seconds // Int agora “tem" o método seconds
  29. 29. Implicits conversions 
 
 
 import scala.concurrent.duration.DurationInt
 
 val time: Duration = 10.seconds
 

  30. 30. 
 import org.scalatest.Matchers._ val resultado: String = …
 resultado should equal ("42")
 Implicits conversions import wildcard
  31. 31. implicit conversions • Conceito similar ao que dá pra fazer em Ruby ou Javascript, estendendo classes mas com tipagem estática! • Você precisa importar explicitamente a conversão • Cuidado para não abusar • Melhor usado em DSLs
  32. 32. Interoperabilidade com Java • Em geral funciona bem • Mas alguns conceitos de Java e Scala são irreconciliáveis • Na prática as 3 maiores dores são: • Código Java que acha legal retornar null • Código Scala que usa coleções Java e vice-versa • Tipos primitivos: Integer e int (Java) <-> Int (Scala)
  33. 33. Scala é complicada como dizem
  34. 34. Scala é complicada como dizem em poucas coisas
  35. 35. Compilador • Poderoso mas “lento” • Pra quem vem de Java, Go e linguagens dinâmicas • Rápido pra quem vem de C++ • Na prática: sbt ~compile ou sbt ~test
  36. 36. Estilos de Scala • Muitas formas de escrever o mesmo código • Um mais cool, outro mais funcional, outro mais imperativo • Qual usar?
  37. 37. Estilos de Scala val lista = List(0, 1, 2, 3, 4)
 
 lista.map( n => n + 1 )
 

  38. 38. Estilos de Scala val lista = List(0, 1, 2, 3, 4)
 
 lista.map { n => n + 1 }
 

  39. 39. Estilos de Scala val lista = List(0, 1, 2, 3, 4)
 
 lista map { n => n + 1 }
 

  40. 40. Estilos de Scala val lista = List(0, 1, 2, 3, 4)
 
 lista.map { _ + 1 }
 

  41. 41. Estilos de Scala val lista = List(0, 1, 2, 3, 4)
 
 lista.map ( _ + 1 )
 

  42. 42. Estilos de Scala 
 
 val lista = List(0, 1, 2, 3, 4)
 
 def add1(n: Int) = n + 1
 
 lista.map (add1)
 

  43. 43. Estilos de Scala 
 
 val lista = List(0, 1, 2, 3, 4)
 
 def add1(n: Int) = n + 1
 
 lista map add1
 

  44. 44. Estilos de Scala lista.map ( n => n + 1 ) <—- Usamos
 lista.map { n => n + 1 } <—- Usamos
 lista map { n => n + 1 }
 lista.map { _ + 1 } 
 lista.map ( _ + 1 ) <—- Usamos 
 lista.map (add1) <—- Usamos
 lista map add1
 

  45. 45. Uso de memória e tempo de startup • Estar na JVM tem vantagens e desvantagens • Uso de memória • Scala piora um pouquinho a situação • Queremos structs! Value Types (Java 9?) • Go e Rust podem ser alternativas em casos que isso é crítico
  46. 46. Scala Avançado e Curva de Aprendizado • Algumas partes da comunidade enveredam demais pelo caminho funcional • Você não é obrigado a usar. Mas a divisão da comunidade não é legal • Com grandes poderes vem grandes responsabilidades • Abuso de features (overloading de operadores) • <o> <!> <<! ># >! >:> >|> (NÃAO, só DSLs onde operador já faz sentido) • Aprendizado • Muito fácil fazer Scala “javado” (mas é um início fácil) • Traz conceitos novos e não familiares para quem vem da linhagem de C: implicits, pattern matching, typeclasses
  47. 47. Scala mudou a forma como programamos
  48. 48. Parar de acessar o que não está lá • NullPointerException (Java) • undefined is not a function (Javascript) • AttributeError: 'NoneType' object has no attribute (Python) • Call to a member function on a non-object (PHP)
  49. 49. Parar de acessar o que não está lá • NullPointerException (Java) • undefined is not a function (Javascript) • AttributeError: 'NoneType' object has no attribute (Python) • Call to a member function on a non-object (PHP)
  50. 50. Null Pointer Exc… NÃO • NullPointerException (Java) • undefined is not a function (Javascript) • AttributeError: 'NoneType' object has no attribute (Python) • Call to a member function on a non-object (PHP) SCALA NÃO TEM !!!!!!!!!
  51. 51. Null Pointer Exc… NÃO • Uso de Option[MeuTipo] quando necessário
  52. 52. Tipagem Estática! • Linguagens com tipagem estáticas pegaram fama de serem verbosas • Não necessariamente • Scala consegue ser tão concisa quanto as linguagens dinâmicas • Tendência de adicionar tipos opcionais nas linguagens dinâmicas • Javascript, PHP, Python • Difícil viver sem um compilador me ajudando
  53. 53. Imutabilidade • Coisas a menos pra guardar na sua cabeça • Não me preocupo se alguém pode ou vai mudar meu objeto • Você pode passar objetos imutáveis pra lá e pra cá de boa • Thread-safe por padrão • Meio que obrigatório para chaves de Map, valores dentro de Set ou Caches em geral • Se você observa um valor numa variável, você sabe que ela foi sempre aquilo
  54. 54. public class Person {
 private final String firstName;
 private final String lastName; String getFirstName() { return firstName; }
 String getLastName() { return lastName; }
 
 public Person(String first, String last) {
 this.firstName = first;
 this.lastName = last;
 }
 
 public int hashCode() {
 return goodHashCode(firstName, lastName);
 }
 public boolean equals(Object o) {
 if ( this == aThat ) return true;
 if ( !(aThat instanceof Person) ) return false;
 Person that = (Person)aThat;
 return EqualsUtil.areEqual(this.firstName, that.firstName) &
 EqualsUtil.areEqual(this.lastName, that.lastName);
 }
 }
  55. 55. case class Person(firstName: String, lastName: String)
  56. 56. imutável é a palavra
  57. 57. Scala é a melhor coisa do mundo?
  58. 58. Scala é a melhor coisa do mundo?
  59. 59. $escapedName = mysql_escape_string($u)
 $escapedCurso = mysql_real_escape_string($c)
 $sql =
 “SELECT * FROM usuarios
 WHERE name LIKE '%”.$escapedName."%’ AND
 curso = ‘“.$escapedCurso;
  60. 60. A minha linguagem/framework/biblioteca não é a melhor possível
  61. 61. Mais conciso e expressivo que Scala é impossível
  62. 62. Mais conciso e expressivo que Haskell é impossível
  63. 63. Programação é sempre um comando seguido do outro
  64. 64. Programação pode ser só (funções (chamando (funções ‘!’))) em Clojure
  65. 65. Programar interfaces é ter que lidar com estado mutável o tempo todo
  66. 66. Programar interfaces é isolar o estado mutável com ReactJS
  67. 67. Ou damos free() na mão ou usamos Garbage Collector
  68. 68. Ou damos free() na mão ou usamos Garbage Collector ou usamos Rust e o seu sistema de ownership
  69. 69. Sempre dá pra melhorar
  70. 70. Obrigado! Dúvidas? @felipehummel felipe.hummel@newsmonitor.com.br
  71. 71. Akka
  72. 72. Akka :) • Simplifica muito o modelo mental para trabalhar com concorrência • Cria "bolhas" onde você pode ser mutável à vontade (com moderação) • Muito bom quando você tem Actors de vida longa e com estado mutável • Não precisa lidar com criação/manutenção de filas (na maior parte do tempo) • Tunar threadpools (dispatchers) não é necessário no início e é bem fácil (via config) • O código do Actor não contém (quase) nada de lógica lidando com concorrência, threads ou threadpool
  73. 73. Akka :( • Toma conta do código (framework) • A relação entre actors não é tão óbvia no código quanto a relação entre objetos num código tradicional (perca de tipagem) • Você pode acabar tunando ExecutionContexts e ThreadPool de qualquer forma. E não é trivial (independente do Akka). • Mais "difícil" de testar • Dá pra isolar algumas coisas e criar determinismo • No final das contas tudo é concorrente • Debugar é bem diferente • Rastrear de onde uma coisa veio, pra onde vai…

×