Por que gosto de scala?




   CodeSimples.com
http://www.erlang-factory.com/upload/presentations/395/ErlangandFirst-PersonShooters.pdf
Hoje somente os “porquês” nada de “como”.
Definições       (Meramente para este contexto)

Concorrência
Programas de rodam em paralelo compartilhando recursos de memória, io e
processamento.


Paralelismo
Programas que não compartilham memória, io e processamento.

Programação imperativa
Na Ciência da Computação, programação imperativa é um paradigma de
programação que descreve a computação como ações, enunciados ou
comandos que mudam o estado (variáveis) de um programa. Muito parecido
com o comportamento imperativo das linguagens naturais que expressam
ordens, programas imperativos são uma sequência de comandos para o
computador executar.

Programação funcional
Em ciência da computação, programação funcional é um paradigma de
programação que trata a computação como uma avaliação de funções
matemáticas e que evita estados ou dados mutáveis. Ela enfatiza a aplicação
de funções, em contraste da programação imperativa, que enfatiza mudanças
no estado do programa.
Desenvolvimento de aplicações concorrentes




Programação imperativa
Starvation e Deadlocks

                        Locado Print Office

                                               Executando

        Find Game             Games           Add new Game




Kiosk                                                         Print Office

                          Locado Kiosk

         Executando

                              Game
         Take tickets                           Add tickets
Race Conditions
  public class RaceCondition {
       private static boolean done;

      public static void main(final String[] args) throws InterruptedException {
           new Thread(
                new Runnable() {
                      public void run() {
                           int i = 0;
                           while(!done) { i++; }
                           System.out.println("Done!");
                      }
                }
           ).start();

          System.out.println("OS:" + System.getProperty("os.name"));
          Thread.sleep(2000);
          done = true;
          System.out.println("flag done set to true");
      }
  }
Fixed Race Conditions
  public class RaceCondition {
       private static volatile boolean done;

      public static void main(final String[] args) throws InterruptedException {
           new Thread(
                new Runnable() {
                      public void run() {
                           int i = 0;
                           while(!done) { i++; }
                           System.out.println("Done!");
                      }
                }
           ).start();

           System.out.println("OS:" + System.getProperty("os.name"));
           Thread.sleep(2000);
           done = true;
           System.out.println("flag done set to true");
      }
  }
Fixed Race Conditions
Básicamente, volatile é usada para indicar que o valor da variável pode ser modificada por outras Threads.

Isso quer dizer que:

O valor da variável não será cacheado pela thread local, todas as leituras e escritas serão feitas na memória
principal

O acesso a variáveis age como se estivesse incluído em um bloco sincronizado.
Complexibilidade acidental sem limites
...
public class Account implements Comparable<Account> {
      private int balance;
      public final Lock monitor = new ReentrantLock();

       public Account(final int initialBalance) { balance = initialBalance; }

       public int compareTo(final Account other) {
             return new Integer(hashCode()).compareTo(other.hashCode());
       }

       public void deposit(final int amount) {
             monitor.lock();
             try { if (amount > 0) balance += amount; } finally { monitor.unlock(); }
       }

       public boolean withdraw(final int amount) {
             try {
                    monitor.lock();
                    if (amount > 0 && balance >= amount) {
                          balance -= amount;
                          return true;
                    }
                    return false;
             } finally { monitor.unlock(); }
       }
}
Fault tolerance
O que fazer quando acontece um erro dentro de um
conjunto de threads ou em uma thread que pertence a um
conjunto?

Escrever o código para esse tipo de tratamento e
complexo.

Talvez    somente      estamos adicionando  mais
complexibilidade e novos pontos de falha do que
realmente tratando o problema.
Scale up / Scale out
Scale up / Scale out
Thread e um recurso muito caro, se vc quer atender muitos usuários.
     public class DieLikeADog {
       private static Object s = new Object();
       private static int count = 0;
       public static void main(String[] argv){
          for(;;){
             new Thread(new Runnable(){
                    public void run(){
                       synchronized(s){
                          count += 1;
                          System.err.println("New thread #"+count);
                       }
                       for(;;){
                          try {
                              Thread.sleep(1000);
                          } catch (Exception e){
                              System.err.println(e);
                          }
                       }
                    }
                 }).start();
          }
       }
     }
Desenvolvimento de aplicações concorrentes




Programação imperativa com aspectos funcionais
Clean code
object CityController extends Controller {

 val cityMapping = ( "name" -> nonEmptyText )

 val cityForm = Form(
   mapping ( "name" -> nonEmptyText, "province" -> nonEmptyText )
   ( (name:String, province:String) => City(Map[String, AnyRef]("name" -> name, "province" -> province)) )
   ( (city:City) => Some((city.name, city.province)) )
 )

 def index = Action { implicit request =>
   val cities = Prevayler.system.executeQuery( FindAllCities() )
   Ok(views.html.nereida.city.index(cities));
 }

 def build = Action {
   Ok(views.html.nereida.city.build(cityForm, Seq[String]("Parana", "Bahia")));
 }

 def create = processJSONRequest {
   implicit json => {
     val city = Prevayler.system.executeTransaction( AddNewCity(json) )
     Created(Json.toJson(city))
   }
 }

 def show(id:String) = processQuery {
   Prevayler.system.executeQuery( FindCityById(id) )
 }
….
Clean code
...
  def edit(id:String) = processQuery {
    Prevayler.system.executeQuery( FindCityById(id) )
  }

 def update(id:String) = processJSONRequest {
   implicit json => {
     val city = Prevayler.system.executeTransaction( UpdateCity(id, json) )
     Created(Json.toJson(city))
   }
 }

 def destroy(id:String) = Action { implicit request =>
   val city = Prevayler.system.executeTransaction( DeleteCity(id) )
   Ok(Json.toJson(city))
 }

….
Clean code
...
  //aux functions
  def processJSONRequest(innerFunction: JsValue => Result) = {
    Action {
      implicit request => {
        Form(cityMapping).bindFromRequest.fold(
          errors => BadRequest(errors.errorsAsJson),
          value => {
            request.body.asJson.map { json =>
              innerFunction(json)
            }.getOrElse {
              BadRequest(Json.toJson(Map("error" -> "invalid json")))
            }
          }
        )
      }
    }
  }

    def processQuery(innerFunction: => Option[City]) = {
      Action {
        innerFunction.map { city =>
          Ok(views.html.nereida.city.build(cityForm.fill( city ), Seq[String]("Parana","Bahia")))
        }.getOrElse {
          BadRequest(Json.toJson(Map("error" -> "invalid json")))
        }
      }
    }
}
No shared state
...
case class City(state:Map[String, AnyRef]) {
  def name: String = state.getOrElse("name","").asInstanceOf[String]

    def province: String = state.getOrElse("province","").asInstanceOf[String]

    def id: String = state.getOrElse("_id","").toString
}
No shared state
….
trait ManageCities {

     def addCity(city:City):City = {
          val newState = city.state + ("_id" -> new ObjectId())
          citiesCollection += newState
          City(newState)
     }

     def cities():List[City] = {
           val list:ArrayBuffer[City] = new ArrayBuffer[City]();
           citiesCollection.find.foreach { cada =>
                  println(cada)
                  list += City(cada) }
           list.toList
     }

     def findCityById(id:String):Option[City] = {
           citiesCollection.findOneByID(id).map { city =>
                 Some[City](City(city))
           }.getOrElse {
                 Some[City](null)
           }
     }

….
No shared state
….
     def removeCityById(id:String):Option[City] = {
           findCityById(id).map { city =>
                 citiesCollection.remove(city.state)
                 Some(city)
           }.getOrElse { Some[City](null) }
     }

     def updateCityById(id:String, name:String):Option[City] = {
          findCityById(id).map { city =>
                city.state.put("name", name)
                citiesCollection.save(city.state)
                Some(city)
          }.getOrElse { Some[City](null) }
     }

     def mongoConnection(): MongoConnection = MongoConnection("localhost", 39717)

     def mongoDB(): MongoDB = mongoConnection()("nereida")

     def citiesCollection(): MongoCollection = mongoDB()("cities")

     implicit def dbObjectToMap(dbObject:DBObject): Map[String,AnyRef] = {
           (dbObject.toMap.asInstanceOf[java.util.Map[String,AnyRef]]).toMap
     }

     implicit def map2DBObject(state:Map[String,AnyRef]): DBObject = {
           MongoDBObject(state.toList).asDBObject
     }
}
Actors (Scala 2.10 unificará com implementação do akka 2.0)
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging

class MyActor extends Actor {
  val log = Logging(context.system, this)
  def receive = {
    case "test" ⇒ log.info("received test")
    case _    ⇒ log.info("received unknown message")
  }
}

object Main extends App {
  val system = ActorSystem("MySystem")
  val myActor = system.actorOf(Props[MyActor], name = "myactor")
  myActor ! “test”
}
Pattern Matching
object MatchTest1 extends Application {
  def matchTest(x: Int): String = x match {
   case 1 => "one"
   case 2 => "two"
   case _ => "many"
  }
  println(matchTest(3))
}



Nada impede o uso de estrategias antes ou depois do matching.
Eu prefiro depois.
Software Transactional Memory
Um STM transforma o heap do Java em uma base de dados transacional onde e possível iniciar
uma transacao begin/commit/rollback .

Muito parecido com banco de dados regulares.

Ela implementa as três primeiras letras contidas em ACID, ou seja

- Atomicidade

- Consistência

- Isolamento
Message passing approach


  Actor    message            Address




                               Mailbox




                             Another Actor

                     Pode existir ou não.
                     Se não existir entra em ação
                     o sistema de tratamento de falhas
Fault Tolerance - “let it crash”




                         Exit signal




              Sistema cai com um erro
Fault Tolerance com supervisores - “let it crash”




                                                 Exit signal


              Supervisor



Supervsores identificam a falha e decidem por:
- Reiniciar o processamento
- Reiniciar o ator
- Reiniciar o sub-sistema.
Scale up / Scale out
Scale up / Scale out
Um MessageDispatcher Akka é o que faz os atores tão leves, este é o motor da
máquina por assim dizer.

Todas as implementações de MessageDispatcher são também um ExecutionContext, o
que significa que eles podem ser usados para executar código arbitrário.

Tenta tirar o melhor proveito possível do recurso Thread, usando adequadamente
Thread Pools.

Como os atores são isolados, fica fácil para subir novas instâncias em outras
máquinas e o serviço de endereçamento fica responsável pela entrega das
mensagens.
Haaa, também tem framework web
Real time applications com Play

def index = WebSocket.using[String] { request =>

    // Just consume and ignore the input
    val in = Iteratee.consume[String]()

    // Send a single 'Hello!' message and close
    val out = Enumerator("Hello!") >>> Enumerator.eof

    (in, out)
}


Chamada simples
ws://localhost:9000/[controller].
Integração com Akka
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")

Exemplo 1
def index = Action {
  Async {
    (myActor ? "hello").mapTo[String].asPromise.map { response =>
      Ok(response)
    }
  }
}

Exemplo2
def index = Action {
  Async {
    Akka.future { longComputation() }.map { result =>
      Ok("Got " + result)
    }
  }
}

Exemplo3
Akka.system.scheduler.schedule(0 seconds, 30 minutes, testActor, "tick")

Obs: cliente fica esperando, mas servidor pode receber nova conexao
Aspectos comerciais
Monitoramento
Estes são meus motivos, descubra os seus
Estes são meus motivos, descubra os seus
Estes são meus motivos, descubra os seus
Obrigado!




CodeSimples.com

App scala

  • 1.
    Por que gostode scala? CodeSimples.com
  • 3.
  • 4.
    Hoje somente os“porquês” nada de “como”.
  • 5.
    Definições (Meramente para este contexto) Concorrência Programas de rodam em paralelo compartilhando recursos de memória, io e processamento. Paralelismo Programas que não compartilham memória, io e processamento. Programação imperativa Na Ciência da Computação, programação imperativa é um paradigma de programação que descreve a computação como ações, enunciados ou comandos que mudam o estado (variáveis) de um programa. Muito parecido com o comportamento imperativo das linguagens naturais que expressam ordens, programas imperativos são uma sequência de comandos para o computador executar. Programação funcional Em ciência da computação, programação funcional é um paradigma de programação que trata a computação como uma avaliação de funções matemáticas e que evita estados ou dados mutáveis. Ela enfatiza a aplicação de funções, em contraste da programação imperativa, que enfatiza mudanças no estado do programa.
  • 6.
    Desenvolvimento de aplicaçõesconcorrentes Programação imperativa
  • 7.
    Starvation e Deadlocks Locado Print Office Executando Find Game Games Add new Game Kiosk Print Office Locado Kiosk Executando Game Take tickets Add tickets
  • 8.
    Race Conditions public class RaceCondition { private static boolean done; public static void main(final String[] args) throws InterruptedException { new Thread( new Runnable() { public void run() { int i = 0; while(!done) { i++; } System.out.println("Done!"); } } ).start(); System.out.println("OS:" + System.getProperty("os.name")); Thread.sleep(2000); done = true; System.out.println("flag done set to true"); } }
  • 9.
    Fixed Race Conditions public class RaceCondition { private static volatile boolean done; public static void main(final String[] args) throws InterruptedException { new Thread( new Runnable() { public void run() { int i = 0; while(!done) { i++; } System.out.println("Done!"); } } ).start(); System.out.println("OS:" + System.getProperty("os.name")); Thread.sleep(2000); done = true; System.out.println("flag done set to true"); } }
  • 10.
    Fixed Race Conditions Básicamente,volatile é usada para indicar que o valor da variável pode ser modificada por outras Threads. Isso quer dizer que: O valor da variável não será cacheado pela thread local, todas as leituras e escritas serão feitas na memória principal O acesso a variáveis age como se estivesse incluído em um bloco sincronizado.
  • 11.
    Complexibilidade acidental semlimites ... public class Account implements Comparable<Account> { private int balance; public final Lock monitor = new ReentrantLock(); public Account(final int initialBalance) { balance = initialBalance; } public int compareTo(final Account other) { return new Integer(hashCode()).compareTo(other.hashCode()); } public void deposit(final int amount) { monitor.lock(); try { if (amount > 0) balance += amount; } finally { monitor.unlock(); } } public boolean withdraw(final int amount) { try { monitor.lock(); if (amount > 0 && balance >= amount) { balance -= amount; return true; } return false; } finally { monitor.unlock(); } } }
  • 12.
    Fault tolerance O quefazer quando acontece um erro dentro de um conjunto de threads ou em uma thread que pertence a um conjunto? Escrever o código para esse tipo de tratamento e complexo. Talvez somente estamos adicionando mais complexibilidade e novos pontos de falha do que realmente tratando o problema.
  • 13.
    Scale up /Scale out
  • 14.
    Scale up /Scale out Thread e um recurso muito caro, se vc quer atender muitos usuários. public class DieLikeADog { private static Object s = new Object(); private static int count = 0; public static void main(String[] argv){ for(;;){ new Thread(new Runnable(){ public void run(){ synchronized(s){ count += 1; System.err.println("New thread #"+count); } for(;;){ try { Thread.sleep(1000); } catch (Exception e){ System.err.println(e); } } } }).start(); } } }
  • 15.
    Desenvolvimento de aplicaçõesconcorrentes Programação imperativa com aspectos funcionais
  • 17.
    Clean code object CityControllerextends Controller { val cityMapping = ( "name" -> nonEmptyText ) val cityForm = Form( mapping ( "name" -> nonEmptyText, "province" -> nonEmptyText ) ( (name:String, province:String) => City(Map[String, AnyRef]("name" -> name, "province" -> province)) ) ( (city:City) => Some((city.name, city.province)) ) ) def index = Action { implicit request => val cities = Prevayler.system.executeQuery( FindAllCities() ) Ok(views.html.nereida.city.index(cities)); } def build = Action { Ok(views.html.nereida.city.build(cityForm, Seq[String]("Parana", "Bahia"))); } def create = processJSONRequest { implicit json => { val city = Prevayler.system.executeTransaction( AddNewCity(json) ) Created(Json.toJson(city)) } } def show(id:String) = processQuery { Prevayler.system.executeQuery( FindCityById(id) ) } ….
  • 18.
    Clean code ... def edit(id:String) = processQuery { Prevayler.system.executeQuery( FindCityById(id) ) } def update(id:String) = processJSONRequest { implicit json => { val city = Prevayler.system.executeTransaction( UpdateCity(id, json) ) Created(Json.toJson(city)) } } def destroy(id:String) = Action { implicit request => val city = Prevayler.system.executeTransaction( DeleteCity(id) ) Ok(Json.toJson(city)) } ….
  • 19.
    Clean code ... //aux functions def processJSONRequest(innerFunction: JsValue => Result) = { Action { implicit request => { Form(cityMapping).bindFromRequest.fold( errors => BadRequest(errors.errorsAsJson), value => { request.body.asJson.map { json => innerFunction(json) }.getOrElse { BadRequest(Json.toJson(Map("error" -> "invalid json"))) } } ) } } } def processQuery(innerFunction: => Option[City]) = { Action { innerFunction.map { city => Ok(views.html.nereida.city.build(cityForm.fill( city ), Seq[String]("Parana","Bahia"))) }.getOrElse { BadRequest(Json.toJson(Map("error" -> "invalid json"))) } } } }
  • 20.
    No shared state ... caseclass City(state:Map[String, AnyRef]) { def name: String = state.getOrElse("name","").asInstanceOf[String] def province: String = state.getOrElse("province","").asInstanceOf[String] def id: String = state.getOrElse("_id","").toString }
  • 21.
    No shared state …. traitManageCities { def addCity(city:City):City = { val newState = city.state + ("_id" -> new ObjectId()) citiesCollection += newState City(newState) } def cities():List[City] = { val list:ArrayBuffer[City] = new ArrayBuffer[City](); citiesCollection.find.foreach { cada => println(cada) list += City(cada) } list.toList } def findCityById(id:String):Option[City] = { citiesCollection.findOneByID(id).map { city => Some[City](City(city)) }.getOrElse { Some[City](null) } } ….
  • 22.
    No shared state …. def removeCityById(id:String):Option[City] = { findCityById(id).map { city => citiesCollection.remove(city.state) Some(city) }.getOrElse { Some[City](null) } } def updateCityById(id:String, name:String):Option[City] = { findCityById(id).map { city => city.state.put("name", name) citiesCollection.save(city.state) Some(city) }.getOrElse { Some[City](null) } } def mongoConnection(): MongoConnection = MongoConnection("localhost", 39717) def mongoDB(): MongoDB = mongoConnection()("nereida") def citiesCollection(): MongoCollection = mongoDB()("cities") implicit def dbObjectToMap(dbObject:DBObject): Map[String,AnyRef] = { (dbObject.toMap.asInstanceOf[java.util.Map[String,AnyRef]]).toMap } implicit def map2DBObject(state:Map[String,AnyRef]): DBObject = { MongoDBObject(state.toList).asDBObject } }
  • 23.
    Actors (Scala 2.10unificará com implementação do akka 2.0) import akka.actor.Actor import akka.actor.Props import akka.event.Logging class MyActor extends Actor { val log = Logging(context.system, this) def receive = { case "test" ⇒ log.info("received test") case _ ⇒ log.info("received unknown message") } } object Main extends App { val system = ActorSystem("MySystem") val myActor = system.actorOf(Props[MyActor], name = "myactor") myActor ! “test” }
  • 24.
    Pattern Matching object MatchTest1extends Application { def matchTest(x: Int): String = x match { case 1 => "one" case 2 => "two" case _ => "many" } println(matchTest(3)) } Nada impede o uso de estrategias antes ou depois do matching. Eu prefiro depois.
  • 25.
    Software Transactional Memory UmSTM transforma o heap do Java em uma base de dados transacional onde e possível iniciar uma transacao begin/commit/rollback . Muito parecido com banco de dados regulares. Ela implementa as três primeiras letras contidas em ACID, ou seja - Atomicidade - Consistência - Isolamento
  • 26.
    Message passing approach Actor message Address Mailbox Another Actor Pode existir ou não. Se não existir entra em ação o sistema de tratamento de falhas
  • 27.
    Fault Tolerance -“let it crash” Exit signal Sistema cai com um erro
  • 28.
    Fault Tolerance comsupervisores - “let it crash” Exit signal Supervisor Supervsores identificam a falha e decidem por: - Reiniciar o processamento - Reiniciar o ator - Reiniciar o sub-sistema.
  • 29.
    Scale up /Scale out
  • 30.
    Scale up /Scale out Um MessageDispatcher Akka é o que faz os atores tão leves, este é o motor da máquina por assim dizer. Todas as implementações de MessageDispatcher são também um ExecutionContext, o que significa que eles podem ser usados para executar código arbitrário. Tenta tirar o melhor proveito possível do recurso Thread, usando adequadamente Thread Pools. Como os atores são isolados, fica fácil para subir novas instâncias em outras máquinas e o serviço de endereçamento fica responsável pela entrega das mensagens.
  • 31.
    Haaa, também temframework web
  • 32.
    Real time applicationscom Play def index = WebSocket.using[String] { request => // Just consume and ignore the input val in = Iteratee.consume[String]() // Send a single 'Hello!' message and close val out = Enumerator("Hello!") >>> Enumerator.eof (in, out) } Chamada simples ws://localhost:9000/[controller].
  • 33.
    Integração com Akka valmyActor = Akka.system.actorOf(Props[MyActor], name = "myactor") Exemplo 1 def index = Action { Async { (myActor ? "hello").mapTo[String].asPromise.map { response => Ok(response) } } } Exemplo2 def index = Action { Async { Akka.future { longComputation() }.map { result => Ok("Got " + result) } } } Exemplo3 Akka.system.scheduler.schedule(0 seconds, 30 minutes, testActor, "tick") Obs: cliente fica esperando, mas servidor pode receber nova conexao
  • 34.
  • 35.
  • 36.
    Estes são meusmotivos, descubra os seus
  • 37.
    Estes são meusmotivos, descubra os seus
  • 38.
    Estes são meusmotivos, descubra os seus
  • 39.