How to launch a product using Scala Lessons Learned I was (am) not a Scala specialist. Launched user facing products using Scala. There are many lessons I’ve learned. αʔϏεΛθϩ͔Β࡞ͬͯେͩͬͨͭͷ͜ͱ
Today’s talk At glance History, we’re learning from history. Architecture, that built from the lessons. Implementation, that we’re using. Executions, form what I’ve learned lessons. ຊͷͷ֓ཁ
So it called “Monorail.” Many pains in the large monolithic system • It’s really easy to break someone’s modules. • grep(1) is the only tool we can believe. • Deploy everything, revert everything. ڊେͳ୯ҰͷγεςϜͰਏ͔ͬͨɻ
to decompose monolithic Ruby on Rails application Rewrite each module in Scala class User < ActiveRecode::Base def self.find(...) $user_service.find(...) end end User.find(1) #=> # ڊେͳ3VCZPO3BJMTΞϓϦέʔγϣϯΛղͯͦ͠ΕͧΕͷϞδϡʔϧΛ4DBMBͰ ॻ͖ͨ͠ɻ
Example code System is complex def main(args: Array[String]) { args match { case Seq("command1") => ... case Seq("command2") => ... case Seq("command3") => ... // Continue 10,000 lines } } ෳࡶͳίʔυͷྫ
Create new functions in the system. Create a new service ৽αʔϏεΛ࡞ΔʹγεςϜʹ৽͍ؔ͠ΛՃ͢Δ def service( request: Request ): Response def newService( request: Request ): Response
Response is not always available immediately. In real world, however. def service(request: Request): Response = ... // How slow is this? val reposes = service(request) ݱ࣮ʹɺ͔͠͠ɺؔͷଈ࠲ʹखʹೖΔΘ͚Ͱͳ͍ɻ
Future works same as the other capsules. Compose Future[+A] • map[A,B](A => B): Future[B] • flatMap[A,B](A => Future[B]): Future[B] • join[A,B](Future[A], Future[B]): Future[(A,B)] • collect[A](Seq[Future[A]]): Future[Seq[A]] 'VUVSFଞͷ4DBMBͷίϨΫγϣϯͱಉ༷ʹ߹Մೳɻ A Future[A] B Future[B] map A Future[A] B Future[B] flatMap
Deal with complexity “Functional” Architecture Divide-and-rule Function as a service Compose response Future[+A] to make a logic asynchronously ʮؔతͳʯΞʔΩςΫνϟ
• Define functions • Resolve functions • Implement functions • Instantiate functions • Discover functions Things we need to call function γεςϜ͕ඞཁͱ͍ͯ͠Δ͜ͱ
Thrift, an IDL to define models and services Scrooge, a Thrift code generator in Scala Thrift, Scrooge Define functions ఆٛʹ5ISJGUΛ͏ɻ4DSPPHFͰ4DBMBͷίʔυੜɻ
Finagle, a RPC core library. Finatra, a framework using Finagle TwitterServer (HTTP server and Thrift server) Guice dependency injection Finagle, Finatra Implement functions ࣮ʹ'JOBHMFΛϕʔεʹ'JOBUSBΛ͍ͬͯΔ
Instantiate functions Mesos, Aurora Mesos, a cluster manager for data center. Aurora framework, a job scheduler. Define job in aurora DSL file. .FTPTͱ"VSPSBϑϨʔϜϫʔΫͰΠϯελϯεΛཧ
Discover functions Zookeeper Zookeeper, a reliable directory for service discovery. Announced by Aurora Resolved by Finagle ;PPLFFQFSͰαʔϏεΛൃݟ͢Δɻ"VSPSBͰΠϯελϯεΛ໊લొͯ͠ɺ'JOBHMF Ͱղܾ
Things we need to build services Implementations Define in Thrift, manage every things in a single Git repository. Finatra to implement services. Aurora to run services and discovery. αʔϏεΛ࡞Δͷʹඞཁͳ࣮
Integrate everything at first. Build app from top to bottom Bad assumption may increase tech-debt. Right assumption may reduce tech-debt. Reduces many bad assumptions. ·্͔ͣΒԼ·Ͱͱʹ͔͘ܨ͍Ͱಈ͔͢ɻఆΛͰߟ͑Δ͜ͱΛͰ͖Δ͚ͩݮΒ͢ɻ S S S S S Service Service Service Service Service
Create many instances with modification on Aurora Run devel instances Work-in-progress instance is okay. Working mock is better than tech-doc to deal with product manager, sometimes. ։ൃ༻ΠϯελϯεΛ࣮ߦ͓ͯ͘͠ɻ
Override services for debugging and testing Dtab A delegation table. Override finagle resolver to swap services. Dtab-local: header for HTTP request. %UBCΛ໊ͬͯલղܾΛ্ॻ͖ͯ͠αʔϏεΛϥϯλΠϜʹೖΕସ͑Δ
User interface is a representation of internal states. Manage internal state. Users changes the internal state. React to the internal state changes. Applying animation, if needed. ෦ঢ়ଶͱมߋͷྲྀΕΛཧ͢Δɻ6*෦ঢ়ଶΛදݱ͢Δͷɻ S Action State Change UI Update Action U User
Single “source” of truth. Mono repo helps it. Identify exact source code by deploy SHA-1. Browse entire source code that the system is using. ୯ҰιʔεϨϙδτϦͰਅ࣮ΛݟΔ commit 8270324cdf0d1e60a83dbefa1de29d89f6107587 commit f40648b9105f7478139694acd0821c15d3315dc2 commit fa0dc865887a02b49576bdc1de57f4ad802d4710 commit ebf31743cbe3008ec311d88aea42b987b0288cd3
Name tells what it is. Define right functions Define API in reasonable way. Naming is really really important. They never read tech-doc. ਖ਼͍ؔ͠ͷఆٛυΩϡϝϯτΑΓେɻ outputImageProviderFromBufferWithPixelFormat:pixelsW ide:pixelsHigh:baseAddress:bytesPerRow:releaseCallba ck:releaseContext:colorSpace:shouldColorMatch:
Manage dependencies. Downstream Estimate QPS and latency. Right timeout and retry policy. Right load banaler ApertureLoadBalancer for lower QPS 214ͱϨΠςϯγΛཧɻϥΠϜΞτͱϦτϥΠͷௐɺϩʔυόϥϯαͷௐɻ S S S S S Service Service Service Service Service
Manage dependencies Upstream Look at CancelledRequestException. Upstream timed out for downstream, it will cancel request and downstream will see this exception. $BODFMMFE3FRVFTU&YDFQUJPOʹҙɻ 6QTUSFBN͕ݫ͍͠λΠϜΞτΛ࣋ͬͯΔՄೳੑ͋Γɻ S S Service Service Timeout! Cancel Exception Timeout Exception
How to launch a product using Scala Lessons Learned 1. Build app from top to bottom to deal with product managers. 2. Manage internal state to deal with designers. 3. Read code to deal with engineers. αʔϏεΛθϩ͔Β࡞ͬͯେͩͬͨͭͷ͜ͱ