Slide 1

Slide 1 text

Scala Use Cases at Hatena גࣜձࣾ͸ͯͳ Takaya Tsujikawa https://www.flickr.com/photos/30081184@N02/3769383676

Slide 2

Slide 2 text

Takaya Tsujikawa (@mechairoi) blog.chairoi.me mechairoi ! - 2009 Hatena Intern (Perl) - 2011 Joined Hatena (Perl) - 2013~ Mackerel team lead engineer (Scala)

Slide 3

Slide 3 text

Table of Contents • Web development with Perl & problems • Why Scala? • Web development with Scala • Pros & Cons

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

• Internet Company 2001~ • Hatena Bookmark • Hatena Blog • Flipnote Hatena etc. • Almost products by Perl

Slide 6

Slide 6 text

Why Perl?

Slide 7

Slide 7 text

– http://www.paulgraham.com/hp.html “We need a language that lets us scribble and smudge and smear, not a language where you have to sit with a teacup of types balanced on your knee and make polite conversation with a strict old aunt of a compiler”

Slide 8

Slide 8 text

Why Perl? (200x) • CPAN • Rapid prototyping • Code density ⛳️ • Duck typing • Perl Community (YAPC etc)

Slide 9

Slide 9 text

a decade later … https://www.flickr.com/photos/josh/11029669/in/photolist-YwJH-dZrHB3-dZro3Y-dZkJSF-dZrn6b-dZkTkH-dZm2se-dZkN5R-dZrFnG-dZm1Lc-aEwYeQ-8cKHdX-aGrYEa-593eo9-eUa2aU- eZXyHe-f1cTP9-dZkQzP-dZrJps-dZkYtg-dZm3gp-dZkAwV-dZkyLc-dZrhAo-dZrjiC-dZrgmN-dZrifq-dZri1Y-dZkS2a-dZkVoM-eUar2C-dZrhLu-a3hhH4-dZruES-eTXXbc-dZkUhB-dZkCJF- dZrmTY-dZrCXS-dZkEYz-dZkZsz-dZkZJZ-dZrrTb-dZkGH2-dZrkZ5-dZrp1N-dZrpNG-dZrHYQ-dZrq5C-dZrsA1/

Slide 10

Slide 10 text

Web applications become more complex https://www.flickr.com/photos/adrian_s/8271860/in/photolist-JoWh-2J1ULn-5MBjL1-7Jb7po-PBm6n-4YxhWQ-ftWYrC-56q8A8-byH7Vo-g6K6Gv-aiH2Kq-oqCruv-wJ9B-6qtmTj- bzvmcN-8SLbUW-4EUk2k-7WsSCV-6WR5CX-bQkpxT-EN7qe-5i3Tcf-aUrm1H-8ZRy8r-aBUFd2-6jBeaS-8N6ZoM-ig1HkK-4Ut5PG-8t8Q6D-5KjrEv-4cTcqP-3feujT-7Bpbqh- atG3JH-22M7W-8cwtgh-5jQDxs-EN7nt-cc87U3-6Zmv7D-4q13tN-9MqM4o-dK4pWN-8agRiA-GK1af-crBgSU-7NVEST-9Lg7jB-6KRFX Business Library Update Legacy Code New features Mobile

Slide 11

Slide 11 text

Resistance to collapse • Coding rule • Code review • Test / Continuous integration • Testing is require but not sufficient • Static code analysis IUUQTXXXqJDLSDPNQIPUPT!/

Slide 12

Slide 12 text

ʊਓਓਓਓਓਓਓਓਓਓਓਓਓʊ ʼɹSudden Runtime Errorɹʻ ʉY^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Yʉ

Slide 13

Slide 13 text

We need static typing https://www.flickr.com/photos/hetgacom/10420400556/in/photostream/

Slide 14

Slide 14 text

Why xxScala?

Slide 15

Slide 15 text

New Project!

Slide 16

Slide 16 text

A New Kind of Application Performance Management

Slide 17

Slide 17 text

Push architecture host1 host2 host3 Mackerel Agent

Slide 18

Slide 18 text

Graphs by roles cpu usage of proxies loadavg5 of apps

Slide 19

Slide 19 text

Monitoring • Mail • Webhook

Slide 20

Slide 20 text

Background • 2013/11 Start • 1 engineer + Outsource • B2B • Low dependency to existing system.(ex. Account system) • Owned service • Less restriction Chance of introduction of new technology

Slide 21

Slide 21 text

Go Graphite PostgreSQL

Slide 22

Slide 22 text

Go Graphite PostgreSQL

Slide 23

Slide 23 text

Requirements • Modern type system • Lots of libraries • Case studies of web development • Member’s Skill

Slide 24

Slide 24 text

Why Scala (1/4) • Modern type system • Static typing • Algebraic data type (case class, sealed trait) • Type inference • Ad hoc polymorphism (implicit conversion) • B2B Safe refactoring and improvement

Slide 25

Slide 25 text

Why Scala (2/4) • Lots of libraries

Slide 26

Slide 26 text

Why Scala (3/4) • Case studies of web development

Slide 27

Slide 27 text

Why Scala (4/4) • Member’s skills • some members had been studied/was interested in Scala • Product must not depend on individual skills

Slide 28

Slide 28 text

Other languages • Java8 • Not available yet • Haskell • Hard to assemble team • Go/Ruby • No modern type system

Slide 29

Slide 29 text

Development with Scala

Slide 30

Slide 30 text

• Fullstack WAF • Routing • Type-safe template engine • play.api.{data.Form, libs.Json} • Pretty error messages • play-auth/stackable-controller

Slide 31

Slide 31 text

• Type safe template engine (Twirl) • Our designer writes Scala expression • Hard for designer • Rewriting Angularjs template • 2.2.1 → 2.2.2 → 2.3.1

Slide 32

Slide 32 text

Design policy • MVC • Classes • object models.Users #create • Side effects • case class models.User (email: String, … ) • Immutable data container • No side effects, no variable.

Slide 33

Slide 33 text

In Perl case ! Side effects are used everywhere

Slide 34

Slide 34 text

Design policy • Less variable, less mutable collection, less partial function ( Option#get ) • User defined types (Tagged Type) • UserId / HostId instead of Int • UserName instead of String Increase guarantee by type

Slide 35

Slide 35 text

In Perl case ! No static typing Just try hard

Slide 36

Slide 36 text

Design policy • Mapping primitive type and domain types by type classes )551CPEZ ! 63* ! %BUBTUPSF "QQMJDBUJPO .PEFM .BQQJOHCZ UZQFDMBTT 4USJOH +40/ KBWBMBOH42- DBTFDMBTTFT 6TFS )PTU

Slide 37

Slide 37 text

Routing GET /hosts/:id controllers.Hosts.retrieve(id: HostId) implicit def hostIdFormat: Formatter[HostId] = new Formatter[HostId] { def bind(key: String, data: Map[String, String]) : Either[Seq[FormError], HostId] = ??? ! def unbind(key: String, value: HostId) = ??? }

Slide 38

Slide 38 text

Modules • Modularize for compile speed ( In progress..) $PSF5ZQFT $PSF .PEFMT $PSF$POUSPMMFST $PSF 7JFXT "MFSU5ZQFT "MFSU .PEFMT "MFSU$POUSPMMFST "MFSU 7JFXT 3PPU 3FWFSTF 3PVUFS

Slide 39

Slide 39 text

• Schema code generation • Type-safe queries and raw queries • All Queries in our product are type-safe • Extends for “FOR UPDATE OF t1” • 1.0.1 → 2.0.0 → 2.0.3 ( → 2.1.0)

Slide 40

Slide 40 text

Build complex queries easily and safely val statusById: Map[AlertId, MonitorStatus] = (for { (log, logLater) <- Tables.alertLogs(orgId) leftJoin Tables.alertLogs(orgId) on { case (log, logLater) => log.createdAt < logLater.createdAt && log.alertId === logLater.alertId } if log.alertId inSetBind entities.map(_.id) if logLater.createdAt.?.isNull } yield (log.alertId, log.status)).list.toMap

Slide 41

Slide 41 text

Build complex queries easily and safely val statusById: Map[AlertId, MonitorStatus] = (for {! (log, logLater) <- Tables.alertLogs(orgId) leftJoin! Tables.alertLogs(orgId) on { case (log, logLater) =>! log.createdAt < logLater.createdAt &&! log.alertId === logLater.alertId! }! if log.alertId inSetBind entities.map(_.id)! if logLater.createdAt.?.isNull! } yield (log.alertId, log.status)).list.toMap

Slide 42

Slide 42 text

Build complex queries easily and safely val statusById: Map[AlertId, MonitorStatus] = (for { (log, logLater) <- Tables.alertLogs(orgId) leftJoin Tables.alertLogs(orgId) on { case (log, logLater) => log.createdAt < logLater.createdAt && log.alertId === logLater.alertId } if log.alertId inSetBind entities.map(_.id) if logLater.createdAt.?.isNull } yield (log.alertId, log.status)).list.toMap

Slide 43

Slide 43 text

Not human readable select x2.x3, x2.x4 from (select x5."updated_at" as x6, x5."status" as x4, x5."alert_id" as x3, x5."created_at" as x7, x5."operator_ id" as x8, x5."id" as x9, x5."trigger" as x10 from "alert_logs" x5, "alerts" x11 where (x11."id" = x5."alert_id") and (x11."org_id" = ?)) x2 left outer join (select x12."updated_at" as x13, x12."status" as x14, x12."alert_id" as x15, x12."created_at" as x16, x12."operator_id" as x17, x12."id" as x18, x12."trigger" as x19 from "alert_logs" x12, "alerts" x20 where (x20."id" = x12."alert_id") and (x20."org_id" = ?)) x21 on (x2.x7 < x21.x16) and (x2.x3 = x21.x15) where (x2.x3 in (?)) and (x21.x16 is null)

Slide 44

Slide 44 text

Not human readable select x2.x3, x2.x4 from (select x5.x6 as x7, x5.x8 as x9, x5.x10 as x11, x5.x12 as x13, x5.x14 as x15, x5.x16 as x17, x5.x18 as x3, x5.x19 as x20, x5.x21 as x22, x5.x23 as x24, x5.x25 as x26, x5.x27 as x28, x5.x29 as x30, x5.x31 as x32, x5.x33 as x34, x5.x35 as x36, x37.x38 as x39, x37.x40 as x4, x37.x41 as x42, x37.x43 as x44, x37.x45 as x46, x37.x47 as x48, x37.x49 as x50, x37.x51 as x52 from (select x53."updated_at" as x6, x53."image_url" as x8, x53."hosts_count_limit" as x10, x53."webhook_url" as x12, x53."enabled_experimental_features" as x14, x53."created_at" as x16, x53."id" as x18, x53."owner_team_id" as x19, x53."name" as x21, x53."gravatar_email" as x23, x53."is_staff" as x25, x53."notification_activates_at" as x27, x53."plan_id" as x29, x53."plan_expired_at" as x31, x53."author_id" as x33, x53."token" as x35 from "orgs" x53) x5 left outer join (select x54."updated_at" as x38, x54."agv_count" as x40, x54."max_count" as x41, x54."total" as x43, x54."created_at" as x45, x54."base_datetime" as x47, x54."id" as x49, x54."org_id" as x51 from "host_metrics_counts" x54) x37 on x5.x18 = x37.x51) x2 left outer join (select x55."updated_at" as x56, x55."agv_count" as x57, x55."max_count" as x58, x55."total" as x59, x55."created_at" as x60, x55."base_datetime" as x61, x55."id" as x62, x55."org_id" as x63 from "host_metrics_counts" x55) x64 on (x2.x3 = x64.x63) and (x2.x48 < x64.x61) where ((x2.x3 in (?)) and (x64.x61 is null)) and (x2.x48 > {ts '2014-09-02 17:27:18.039'}) • Where does code generate this query?

Slide 45

Slide 45 text

In Perl case • No type-safe • Publisher class in SQL Comment SELECT * FROM user WHERE user_id = ?; -- Hatena::User

Slide 46

Slide 46 text

Development flow

Slide 47

Slide 47 text

IDE AND / OR

Slide 48

Slide 48 text

Git Branches operation NBTUFS EFWFMPQ GFBUVSF GFBUVSF 3FMFBTF

Slide 49

Slide 49 text

Git Branches operation NBTUFS EFWFMPQ GFBUVSF GFBUVSF 3FMFBTF No accident on merge

Slide 50

Slide 50 text

In Perl case _人人人人人人人人人_ >�Merge without conflicts�< ‾Y^Y^Y^Y^Y^Y^Y^Y‾ Can't locate object method "retrieve_by_id" via package "Entry" at error.pl line 21. Entry->retrieve_by_id(10); Entry->retrieve(id => 10); Entry->retrieve_by_id(20); 3FGBDUPSJOH "EEFEDBMMT

Slide 51

Slide 51 text

Task management • Github issues/pull requests • Tag • Milestone

Slide 52

Slide 52 text

Scrum • Sprint = Milestone • Burn down chart • radekstepan/github-burndown-chart

Slide 53

Slide 53 text

Jenkins/CI • Test & Packaging parallel • 1h → 20min • Git integration

Slide 54

Slide 54 text

git-pr-release • Auto generate pull-request • master ← develop • Check list / issues • Everyone can deploy • motemen/git-pr-release

Slide 55

Slide 55 text

Deploy • Restarting JVM is slow → 502 • Capistrano • Custom deploy strategy • scp jar files from Jenkins • Rolling deploy • daemontools https://www.flickr.com/photos/gsfc/9807812154/in/photolist-fWFARy-dBeVvk-96iJmd-atSZgv-hFZzw8-aoA2hH-j2aiC2-mrQV5-kwW6fT-9MP2Ju-edaJM7-M3WWJ-kmUfnB-dxxRza- Cjb4u-4YSS4-8JpmiE-4yjdpB-bbibXF-btu7MA-bGoWje-kTaXqi-jJpjHn-5RV54-4rMctW-bGoWnD-ecFBPp-9Yf9KD-9XsGPA-LVDt-aRcVjM-5xgexk-9S6d4F-4y4qNv-eZwRu-osQq9g-ebMkug- ed9XJo-qyM6W-aUyKZH-4cxiEU-bGoWsk-btu7F1-776kcJ-9zuC1x-j2bH1R-bypWd7-e6BdUN-bGoWeX-btu7A7

Slide 56

Slide 56 text

In Perl case • Capistrano • git clone • Server::Starter • Graceful restart

Slide 57

Slide 57 text

Scala Pros & Cons

Slide 58

Slide 58 text

Pros https://www.flickr.com/photos/quinndombrowski/5200218267/in/photolist-6k8go4-a3y271-8VwtHD-skiqN-nN34SF-bveV1T-cjNRK9-oddpGc-6SXagE-fea96C-6MLPeT-a7pJhj-wDorR- a55adA-8uYbhg-4HP2Qm-dhuorr-aYXd4F-eLGkd-e4eFKc-9ugzpc-6MZ9UU-bWXfCV-9GH9mD-59UEA7-aG95zM-3fJmjC-cHPX65-8aBfdr-j7GYKE-e6ViAm-bAhx1p-feQRPa-92JZzp-kLtFHa- XWd9L-9zbeGs-9DdEqR-8maR73-nBgwNS-8WFsTq-7wSNi8-MvvjP-5DMyrq-8Kowmj-54rxHi-BqUvC-fLbCYs-7F9di2-nR8Kt4

Slide 59

Slide 59 text

Pros • Peace of Mind • Refactoring/Upgrade is easy • Can focus to architecture/design and logic in review • Functional programming • Collection libraries

Slide 60

Slide 60 text

Cons • Slow compilation • modularize • high spec machine

Slide 61

Slide 61 text

Cons • Require Java/JVM literacy • Rich language functions • Hard to learn • De-facto standard Job queue? • Mocking is difficult in tests

Slide 62

Slide 62 text

Conclusion ! Cannot go back to Perl

Slide 63

Slide 63 text

Any Question?

Slide 64

Slide 64 text

We are hiring