Slide 1

Slide 1 text

Making of SaaS Backend guided by PofEAA @dnskimox PofEAAで考える SaaSバックエンドの作り方

Slide 2

Slide 2 text

Who am I ● Tanga Kenichi ● @dnskimox ● Backend Developer ● SaaS for contract management 2 自己紹介

Slide 3

Slide 3 text

PofEAA The book about powerful design patterns for “Enterprise Application” written by Martin Fowler at 2002. 3 邦題:エンタープライズアプリケーションアーキテクチャ パターン

Slide 4

Slide 4 text

What is the “Enterprise application”? Enterprise application does: ● store vary data ● manage huge data ● accept many requests at a time ● collaborate with other Enterprise applications 4 エンタープライズアプリケーションとは

Slide 5

Slide 5 text

Enterprise Application ≒ Web Service 5 Especially a web service requiring massive development ほぼWEBサービスのこと

Slide 6

Slide 6 text

A web service of this session’s subject is... このセッションで取り上げる架空のWEBサービス *this service is fictitious MakeInvoice

Slide 7

Slide 7 text

Contents 7 About MakeInvoice The way we have managed such a large, complex application Architecture in MakeInvoice Service description about MakeInvoice, invoice creation and management SaaS Design patterns that will be worthwhile to adopt to MakeInvoice Adoptable Patterns 1 2 3 目次

Slide 8

Slide 8 text

1. About MakeInvoice Service description about MakeInvoice, invoice creation and management SaaS MakeInvoiceについて

Slide 9

Slide 9 text

CloudSign Salesforce Dashboard(SPA) Client Service MakeInvoice

Slide 10

Slide 10 text

Simple Domain Model 素朴なドメインモデル

Slide 11

Slide 11 text

Slightly Complex Domain Model やや複雑なドメインモデル

Slide 12

Slide 12 text

More Complex Domain Model さらに複雑なドメインモデル

Slide 13

Slide 13 text

And More... さらにさらに

Slide 14

Slide 14 text

This logic has to consider: ● difference between regular and discount item ● tax calculation ● to manipulate a template of document Invoice Creation 請求書生成のビジネスロジック

Slide 15

Slide 15 text

This logic has to consider: ● partial payment ● overpaying ● carrying over to next month Reconciliation 入金消込のビジネスロジック

Slide 16

Slide 16 text

This logic has to consider: ● resending invoice ● how to handling old invoice ● difference between total price and price paid partially Demand for Payment 支払催促のビジネスロジック

Slide 17

Slide 17 text

Combine and Split Invoice 請求書の結合と分割のビジネスロジック

Slide 18

Slide 18 text

Large domain model structure Complex business logic Requests from dashboard, from Salesforce, from other services using MakeInvoice Some other SaaS to have to connect 18 Characteristics  of MakeInvoice backend API MakeInvoiceのバックエンドAPIの特徴

Slide 19

Slide 19 text

2. Architecture in MakeInvoice The way we have managed such a large, complex application MakeInvoiceのアーキテクチャ

Slide 20

Slide 20 text

Clean Architecture

Slide 21

Slide 21 text

Domain Layer UseCase Layer Primary / Secondary Adapter Code for technical interest and implementation i.e: Http, gRPC, RDB, KVS Represents common use-cases using domain model Contains only “pure” domain concepts and logic Dependency direction 各レイヤーの責務 依存の方向性

Slide 22

Slide 22 text

Hexagonal architecture This architecture aims to: ● receive request from variety of clients ● reuse essential application code ● write data on several data storages or send to other system 22 https://blog.tai2.net/hexagonal_architexture.html ヘキサゴナルアーキテクチャ

Slide 23

Slide 23 text

Hexagonal architecture ● Primary Adapters are adapters to communicate with primary actor. ● Secondary Adapters are adapters to communicate with supporting actor (also known as secondary actor). 23 https://blog.tai2.net/hexagonal_architexture.html プライマリアダプターと主アクター セカンダリアダプターと支援アクター

Slide 24

Slide 24 text

3. Adoptable Patterns Design patterns that will be worthwhile to adopt to MakeInvoice 適用可能なパターン

Slide 25

Slide 25 text

Domain Layer UseCase Layer Primary / Secondary Adapter DataMapper, SingleTableInheritance, EmbeddedValue, SerializedLOB, DependentMapping, DataTransferObject, ServiceStub (Nothing) DomainModel, POJO, ValueObject, Repository レイヤー毎のパターン

Slide 26

Slide 26 text

Representing domain model is simple, unless domain classes depend on any library or framework. Domain Layer ドメインレイヤー

Slide 27

Slide 27 text

会社、顧客、書類、請求書、請求書品目

Slide 28

Slide 28 text

“We wondered why people were so against using regular objects in their systems and concluded that it was because simple objects lacked a fancy name. ” 28 https://martinfowler.com/bliki/POJO.html Plain Old Java Object (POJO) 昔からある単なるJavaオブジェクト

Slide 29

Slide 29 text

case class Invoice ( id: DocumentId, companyId: CompanyId, customerId: CustomerId, items: Seq[InvoiceItem], billingDate: LocalDate, billingDueDate: LocalDate, status: InvoiceStatus ) extends Document abstract class Document { val id: DocumentId val companyId: CompanyId val customerId: CustomerId }

Slide 30

Slide 30 text

“An object model of the domain that incorporates both behavior and data.” 30 Domain Model https://www.martinfowler.com/eaaCatalog/domainModel.html ドメインモデル

Slide 31

Slide 31 text

case class Invoice ( id: DocumentId, companyId: CompanyId, customerId: CustomerId, items: Seq[InvoiceItem], billingDate: LocalDate, dueDate: LocalDate, status: InvoiceStatus ) extends Document { def totalPrice: Money = ??? def subtotal: Money = ??? def tax: Money = ??? def combine(other: Invoice): Invoice = ??? def split(prices: Seq[Money]): Seq[Invoice] = ??? }

Slide 32

Slide 32 text

“A small simple object, like money or a date range, whose equality isn't based on identity.” 32 Value Object https://www.martinfowler.com/eaaCatalog/valueObject.html 値オブジェクト

Slide 33

Slide 33 text

case class Money( currency: Currency, value: BigDecimal ) case class Currency( currencyCode: String )

Slide 34

Slide 34 text

case class Money( currency: Currency, value: BigDecimal ) { def plus(other: Money): Money = ??? def minus(other: Money): Money = ??? def mul(factor: BigDecimal): Money = ??? def div(factor: BigDecimal): Money = ??? }

Slide 35

Slide 35 text

case class Address( countryCode: CountryCode, zipCode: ZipCode, city: String, address1: String, address2: String ) { def isSame(other: Address): Boolean = ??? }

Slide 36

Slide 36 text

“Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.” 36 https://www.martinfowler.com/eaaCatalog/repository.html Repository リポジトリ

Slide 37

Slide 37 text

書類リポジトリ

Slide 38

Slide 38 text

trait DocumentRepository { def store[R :_trantask :_error](document: Document): Eff[R, Document] def resolve[R :_trantask :_error](id: DocumentId): Eff[R, Document] def matching[R :_trantask :_error](criteria: Criteria): Eff[R, Seq[Document]] } case class Criteria( companyId: Option[CompanyId], customerId: Option[CustomerId], documentType: Option[DocumentType] ) { def isSatisfiedBy(document: Document): Boolean = ??? }

Slide 39

Slide 39 text

What is EFF? 39 For more information, please go to Yoshimura‘s session. EFFについて

Slide 40

Slide 40 text

Design Domain Layer from Domain Model not from database. 40 ドメインモデルから設計を始める

Slide 41

Slide 41 text

otherwise 41 さもないと

Slide 42

Slide 42 text

“By pulling all the behavior out into services, however, you essentially end up with Transaction Scripts, and thus lose the advantages that the domain model can bring. ” 42 https://martinfowler.com/bliki/AnemicDomainModel.html AnemicDomainModel ドメインモデル貧血症

Slide 43

Slide 43 text

This layer contains business transaction only. So meaningful patterns adopted here would be honestly nothing. UseCase Layer ユースケースレイヤー

Slide 44

Slide 44 text

class CreateDocumentUseCase @Inject() ( documentRepository: DocumentRepository, documentFactory: DocumentFactory ) { def execute[R :_trantask :_error]( documentType: DocumentType, ... ): Eff[R, Unit] = for { document <- documentFactory.create(documentType, ...) _ <- documentRepository.store(document) } yield () }

Slide 45

Slide 45 text

Secondary Adapter Main concern in this layer probably is mapping objects to/from relational database. Also clients to request to external service is in this layer. セカンダリアダプター

Slide 46

Slide 46 text

“A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself.” 46 https://www.martinfowler.com/eaaCatalog/dataMapper.html Data Mapper データマッパー

Slide 47

Slide 47 text

“An object that sets up a communication between two independent objects.” 47 https://www.martinfowler.com/eaaCatalog/mapper.html Mapper マッパー

Slide 48

Slide 48 text

Table schema is free from domain model. 48 テーブルスキーマは自由

Slide 49

Slide 49 text

Separation of Concerns 49 関心の分離

Slide 50

Slide 50 text

class DocumentRepositoryImpl { def store[R :_trantask :_error](document: Document): Eff[R, Document] = ??? def resolve[R :_trantask :_error](id: DocumentId): Eff[R, Document] = ??? def matching[R :_trantask :_error](criteria: Criteria): Eff[R, Seq[Document]] = ??? }

Slide 51

Slide 51 text

Impedance Mismatch 51 Object Oriented World ● Abstraction ● Composition Relational DB World ● Set ● Relation インピーダンスミスマッチ

Slide 52

Slide 52 text

Impedance Mismatch 52 Object Oriented World ● Abstraction ● Composition Relational DB World ● Set ● Relation 抽象化を集合と関係の世界へ

Slide 53

Slide 53 text

抽象クラスの書類

Slide 54

Slide 54 text

“Represents an inheritance hierarchy of classes as a single table that has columns for all the fields of the various classes.” 54 https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html Single Table Inheritance シングルテーブル継承

Slide 55

Slide 55 text

書類テーブル

Slide 56

Slide 56 text

書類の種類を増やす

Slide 57

Slide 57 text

書類テーブル Ver.2

Slide 58

Slide 58 text

Many nullable fields! 58 Nullを許容するフィールドがたくさん

Slide 59

Slide 59 text

“Represents an inheritance hierarchy of classes with one table for each class.” 59 https://www.martinfowler.com/eaaCatalog/classTableInheritance.html Class Table Inheritance クラステーブル継承

Slide 60

Slide 60 text

書類テーブル Ver.3

Slide 61

Slide 61 text

Impedance Mismatch 61 Object Oriented World ● Abstraction ● Composition Relational DB World ● Set ● Relation コンポジションを集合と関係の世界へ

Slide 62

Slide 62 text

顧客に含まれる名前オブジェクト

Slide 63

Slide 63 text

“Maps an object into several fields of another object's table.” 63 https://www.martinfowler.com/eaaCatalog/embeddedValue.html Embedded Value 組込バリュー

Slide 64

Slide 64 text

顧客テーブル

Slide 65

Slide 65 text

顧客に含まれる住所オブジェクト

Slide 66

Slide 66 text

x 1? 顧客テーブル Ver.2

Slide 67

Slide 67 text

“Saves a graph of objects by serializing them into a single large object (LOB), which it stores in a database field.” 67 https://www.martinfowler.com/eaaCatalog/serializedLOB.html Serialized LOB シリアライズドLOB

Slide 68

Slide 68 text

x ∞ 顧客テーブル Ver.3

Slide 69

Slide 69 text

Not bad 69 悪くない

Slide 70

Slide 70 text

But... 70 でも

Slide 71

Slide 71 text

● Managing scheme is difficult. ● Adding and removing property is problematic. ● Result of SQL is not human friendly. ● Managing scheme is almost unnecessary. ● New table is not needed. ● Table joining does not occur. ● Object count is unlimited. Using serialized field has pros and cons Pros Cons シリアライズされたフィールドの功罪

Slide 72

Slide 72 text

“Has one class perform the database mapping for a child class.” 72 https://www.martinfowler.com/eaaCatalog/dependentMapping.html Dependent Mapping 依存マッピング

Slide 73

Slide 73 text

x ∞ 顧客テーブル Ver.4 Dependent Object

Slide 74

Slide 74 text

● When owner object is updated, dependent objects are all deleted then re-inserted. ● When owner object is deleted, dependent objects are deleted cascadingly. ● Any object except for owner cannot associate with dependent object. ● Dependent object's table has foreign key for owner's table. Dependent object's characteristic Association/Relation Update/Delete 依存オブジェクトの特徴

Slide 75

Slide 75 text

“Removes dependence upon problematic services during testing. WSDL ” 75 https://www.martinfowler.com/eaaCatalog/dependentMapping.html Service Stub サービススタブ

Slide 76

Slide 76 text

クラウドサインサービス

Slide 77

Slide 77 text

Primary Adapter This layer is so-called "Presentation Layer". To parse request from client and to compose response are its responsibility. Also main App for running batch program is contained here. プライマリアダプター

Slide 78

Slide 78 text

“Provides a coarse-grained facade on fine-grained objects to improve efficiency over a network.” 78 https://www.martinfowler.com/eaaCatalog/remoteFacade.html Remote Facade

Slide 79

Slide 79 text

class DocumentController @Inject() ( createDocumentUseCase: CreateDocumentUseCase, getDocumentUseCase: GetDocumentUseCase ) extends AkkaHttpController { def routes: Route = pathPrefix("DocumentService") { post { path("CreateDocument") { createDocument } ~ path("GetDocument") { getDocument } } } private def createDocument: Route = ??? private def getDocument: Route = ??? }

Slide 80

Slide 80 text

Split endpoints moderately coarse grained. 80 荒い粒度でエンドポイントを分割する

Slide 81

Slide 81 text

“An object that carries data between processes in order to reduce the number of method calls.” 81 https://www.martinfowler.com/eaaCatalog/dataTransferObject.html Data Transfer Object データ変換オブジェクト

Slide 82

Slide 82 text

ドキュメントアセンブラ ドキュメントDTO

Slide 83

Slide 83 text

DTO structure is free from domain model. 83 DTOの構造は自由

Slide 84

Slide 84 text

Separation of Concerns 84 関心の分離

Slide 85

Slide 85 text

Domain Model Repository ValueObject DataMapper SingleTableInheritanse ClassTableInheritanse EmbededValue SerializedLOB DependentMapping DTO Remote Facade Putting It All Together 全てのパターンをひとつに SPA DB UseCase Service Stub Other SaaS

Slide 86

Slide 86 text

Conclusion 86 PofEAA put forward many useful patterns for complex web application. But , as Fowler writes, these patterns have pros and cons. So we have to keep thinking which patterns to use or not use any pattern. Use this advice to prod your thinking. In the end you have to make, and live with, the decisions yourself. One good thing is that your decisions are not cast forever in stone. - Martin Fowler 結論

Slide 87

Slide 87 text

Now, you have learned main concept to write code of      backend. 87 もうScalebaseのバックエンドを書けるはず

Slide 88

Slide 88 text

Join us! ご応募お待ちしております!

Slide 89

Slide 89 text

Does anyone have any questions? @dnskimox dnskimox.hateblo.jp 89 Thanks! ご清聴ありがとうございました!

Slide 90

Slide 90 text

Reference literature ● https://www.amazon.co.jp/dp/B008OHVDFM ● https://www.martinfowler.com/eaaCatalog/index.html ● https://bliki-ja.github.io/pofeaa/CatalogOfPofEAA_Ja/ ● https://martinfowler.com/bliki/POJO.html ● https://martinfowler.com/bliki/AnemicDomainModel.html ● https://blog.tai2.net/hexagonal_architexture.html ● http://atnos-org.github.io/eff/index.html ● https://github.com/google/guice 90 参考文献