Upgrade to Pro — share decks privately, control downloads, hide ads and more …

FaaS上のコードをもっとシンプルに書くためのトランスパイラ / Serverless Meetup Tokyo #13

FaaS上のコードをもっとシンプルに書くためのトランスパイラ / Serverless Meetup Tokyo #13

Serverless Meetup Tokyo #13での資料です
https://serverless.connpass.com/event/138983/

Kosaku Kimura

July 30, 2019
Tweet

More Decks by Kosaku Kimura

Other Decks in Programming

Transcript

  1. トランスパイラ ソース(JavaScript)からソース(JavaScript)に変換するコンパイラ  TypeScript: 型あり → 型なし  Prettier: ぐちゃぐちゃ

    → きれい  webpack: 大きい(読める) → 小さい(読めない)  Babel: 新しい(まだない) → 古い(もうある) 現代のJavaScript開発環境を支えている大事な技術 Copyright 2019 FUJITSU LABORATORIES LTD. 3
  2. 新しい → 古い はこんな感じ Copyright 2019 FUJITSU LABORATORIES LTD. 4

    async function foo() { await bar(); } var _asyncToGenerator = function (fn) { ... }; var foo = _asyncToGenerator(function* () { yield bar(); }); https://babeljs.io/docs/en/babel-plugin-transform-async-to-generator
  3. シンプルなもの → ちゃんと動くもの が欲しい  サーバレスだとできるだけコードを書きたくない  けど全く書かないわけにはいかない  ビジネスロジックは書かないといけない.あとAPI非同期呼び出しとか

     JavaScriptの非同期処理難しい  コールバック, Promise, generator/yield, async/await・・・  デプロイするものを軽くしたいから新しい依存関係を増やしたくない  いい感じのシンプルさで書けて、実際の複雑な非同期処理に書き換えてくれ るようなトランスパイラって無いかなー Copyright 2019 FUJITSU LABORATORIES LTD. 5
  4. あります(作りました) Escapin the TranspilerTM https://github.com/FujitsuLaboratories/escapin yarn global add escapin ||

    npm install –g escapin 特長  Serverless Frameworkと連携  DynamoDB Table, S3 Bucketが連想配列になる  Swagger/OASで書かれたREST API呼び出しがJSONオブジェクト操作になる  非同期処理のことを忘れられる Copyright 2019 FUJITSU LABORATORIES LTD. 6
  5. Type Information Escapinのトランスパイル手順 const items = {}; ... items[id] =

    obj; ... ... await new Promise( (resolve, reject) => { Storage.put({ name: "items", key: id, value: obj }, (err, res) =>{ if (err) reject(err); else resolve(res); }); ... AST Walker / テンプレート (Babel traverse/templateを使用) platform: a-cloud 元のコード serverless.yml 設定ファイル function function type Storage#put error-first-callback FaaSにデプロイする コード コールバック分解 詳細化 非同期化 Copyright 2019 FUJITSU LABORATORIES LTD. 関数型判別 (TypeScript Compiler APIを使用) (c) 2019 Serverless, Inc. 7
  6. コールバック分解  中途半端な非同期をいったん同期側に全部倒す Copyright 2019 FUJITSU LABORATORIES LTD. func(arg, (err,

    data) => { if (err) { handleError(err); return; } doSomething(data); }); try { const data = func(arg); doSomething(data); } catch (err) { handleError(err); } 8
  7. 詳細化 – API Method Path GET POST PUT DELETE /items

    api.items api.items(body) api.items = body delete api.items /items/:id api.items[id] api.items[id](body) api.items[id] = body delete api.items[id] /items/:id with params api.items [id][params] api.items [id][params](body) api.items [id][params] = body delete api.items [id][params] Copyright 2019 FUJITSU LABORATORIES LTD. import api from 'https://path/to/swagger.yaml'; const item = api.items[id]; const item = request({ 'uri': `https://api.com/v1/items/${id}`, 'method': 'get', 'contentType': 'application/json', 'headers': { 'authorization': 'Basic ... ' } });  Swagger/OASを読み込んで型決め 9
  8. Function Lambda export function foo(bar) {…} createFunction 詳細化 – AWS

    Object DynamoDB S3 export const obj: dynamodb|s3 = {} createTable createBucket obj[id] getItem getObject obj[id] = … putItem putObject delete obj[id] deleteItem deleteObject Copyright 2019 FUJITSU LABORATORIES LTD. 10
  9. 関数型判別 以下の4種類に緩く判別(TypeScript Compiler API使ってます) 1. Asynchronous: Promiseを返すもの  Axios.get等 2.

    Error-first-callback: 第一引数がerrorオブジェクトなコールバックを引 数に持つもの(Promisifyできるもの)  Request, AWS SDK関連 3. General-calback: Error-firstでないコールバックを引数に持つもの  Arrayのmap, forEach等 4. General: それ以外 Copyright 2019 FUJITSU LABORATORIES LTD. 11
  10. 非同期化 Function Type DynamoDB#getItem error-first-callback Array#map general-callback … … 元のコード

    非同期化されたコード 関数型 Copyright 2019 FUJITSU LABORATORIES LTD. const data = new DynamoDB().getItem({ TableName: 'csv', }); const keys = data.Items.map( item => item.key.S); const _data = await new Promise((resolve, reject) => { new DynamoDB().getItem({ TableName: 'csv', … }, (err, data) => { if (err) reject(err); else resolve(data); }); }); const keys = _data.Items.map( item => item.key.S); 12