SlideShare une entreprise Scribd logo
1  sur  40
Télécharger pour lire hors ligne
ES2015 の class で
アプリケーションを
書いてみた話
Hiroyuki Kusu ( @hkusu_ )
YAPC::Asia Hachioji 2016 mid in Shinagawa
7/3 LT
【YAPC::Asia Hachioji 2016】ES2015のclassでアプリケーションを書いてみた話
■ 〜2015年12月
・Android アプリの開発
■ 2016年1月〜
・JavaScript アプリケーションの開発
Javaに
慣れ親む
わりと Java っぽいクラスベースの
オブジェクト志向でいけた!
(あくまで「ぽい」)
ES2015
■ ES2015 で書く
・Babel (トランスパイラ)
・Browserify (ブラウザ用の場合)
■ エディタ
・WebStorm (JetBrains 社製 IDE)
・like Android Studio
前提となる環境
class
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
getName() {
return this.name
}
getAge() {
return this.age
}
hello() {
return `こんにちは! ${this.name} さん`
}
}
export default Person
Person.js
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
getName() {
return this.name
}
getAge() {
return this.age
}
hello() {
return `こんにちは! ${this.name} さん`
}
}
export default Person
Person.js
コンストラクタ
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
getName() {
return this.name
}
getAge() {
return this.age
}
hello() {
return `こんにちは! ${this.name} さん`
}
}
export default Person
Person.js
インスタンス変数
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
getName() {
return this.name
}
getAge() {
return this.age
}
hello() {
return `こんにちは! ${this.name} さん`
}
}
export default Person
Person.js
インスタンスメソッド
class SomeUtil {
static isObject(arg) {
return typeof arg === 'object' && arg !== null && !Array.isArray(arg);
}
}
export default SomeUtil
SomeUtil.js
クラスメソッド
import Person from './Person'
class Men extends Person {
hello() {
return `おす! ${this.name} さん`
}
}
export default Men
Men.js
継承
1ファイル、1クラス(原則)
import Person from './Person'
import SomeUtil from './SomeUtil'
// …
const person = new Person('山田', 45)
クラスをインポートして利用
列挙型
(ぽいもの)
const Week = {
SUN: Symbol(),
MON: Symbol(),
TUE: Symbol(),
WED: Symbol(),
THU: Symbol(),
FRI: Symbol(),
SAT: Symbol(),
}
export default Week
import Week from './Week'
// …
const myWeek = Week.SUN
Week.js
利用例
const Action = {
SEARCH: Symbol(),
REGISTER: Symbol(),
UPDATE: Symbol(),
DELETE: Symbol(),
}
export default Action
Action.js
キーとして利用
(例えば Redux などで)
Singleton
import axios from 'axios'
import { config } from './../config/Config'
class QiitaApiService {
constructor(config) {
this.baseUrl = config.QIITA_BASE_URL
}
search(searchWord, perPage = 10) {
return this.httpGet(`search?q=${searchWord}&per_page=${perPage}`)
}
httpGet(query) {
return axios.get(`${this.baseUrl}/${query}`)
}
}
export default QiitaApiService
export const qiitaApiService = new QiitaApiService(config)
QiitaApiService.js
インスタンス化したものを export
import { qiitaApiService } from './service/QiitaApiService'
// …
qiitaApiService.search('JavaScript', 10)
.then(() => {
// ...
})
アプリケーション内で
インスタンスが共有される
アクセス修飾子
(private / protected)
with WebStorm
& JSDoc
import axios from 'axios'
import { config } from './../config/Config'
class QiitaApiService {
constructor(config) {
/** @private */
this.baseUrl = config.QIITA_BASE_URL
}
search(searchWord, perPage = 10) {
return this.httpGet(`search?q=${searchWord}&per_page=${perPage}`)
}
/**
* @private
*/
httpGet(query) {
return axios.get(`${this.baseUrl}/${query}`)
}
}
// …
QiitaApiService.js
private変数
privateメソッド
【YAPC::Asia Hachioji 2016】ES2015のclassでアプリケーションを書いてみた話
型チェック
with WebStorm
& JSDoc
// …
class QiitaApiService {
/**
* @constructor
* @param {Config|SpecConfig} config
*/
constructor(config) {
/** @private */
this.baseUrl = config.QIITA_BASE_URL
}
/**
* @param {string} searchWord
* @param {number} [perPage=10]
* @returns {promise}
*/
search(searchWord, perPage = 10) {
return this.httpGet(`search?q=${searchWord}&per_page=${perPage}`)
}
/**
* @param {string} query
* @returns {promise}
* @private
*/
httpGet(query) {
return axios.get(`${this.baseUrl}/${query}`)
}
}
// …
【YAPC::Asia Hachioji 2016】ES2015のclassでアプリケーションを書いてみた話
/** @type {QiitaApiService} */
export const qiitaApiService = new QiitaApiService(config)
型が迷子になったら @type で指定
Test
Repository層
Service層
Dependency injection
Config
利用 利用 利用
クラス内で出来るだけ別クラスを new() しない
static な状態の保持は可能な限り避ける
import { config } from './../config/Config'
import ItemRepository from './../repository/ItemRepository'
import QiitaApiService from './../service/QiitaApiService'
const itemRepository = new ItemRepository(new QiitaApiService(config))
Dependency injection
// ...
describe('ItemRepository', () => {
let itemRepository
let qiitaApiService
before(() => {
qiitaApiService = new QiitaApiService(config)
itemRepository = new ItemRepository(qiitaApiService)
});
describe('#getItemByWord', () => {
let qiitaApiServiceSearchStub
before(() => {
qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search')
qiitaApiServiceSearchStub.resolves({ result: 'success' })
});
after(() => {
qiitaApiServiceSearchStub.restore()
});
it('be fulfilled', (done) => {
expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled
.then((result) => {
expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99)
expect(result).to.eql({ result: 'success' })
})
.then(done, done)
})
})
})
※Mocha、Chai、Sinon.JS および Promise系のライブラリを利用
class 単位
でテスト
// ...
describe('ItemRepository', () => {
let itemRepository
let qiitaApiService
before(() => {
qiitaApiService = new QiitaApiService(config)
itemRepository = new ItemRepository(qiitaApiService)
});
describe('#getItemByWord', () => {
let qiitaApiServiceSearchStub
before(() => {
qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search')
qiitaApiServiceSearchStub.resolves({ result: 'success' })
});
after(() => {
qiitaApiServiceSearchStub.restore()
});
it('be fulfilled', (done) => {
expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled
.then((result) => {
expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99)
expect(result).to.eql({ result: 'success' })
})
.then(done, done)
})
})
})
メソッドの
テスト
// ...
describe('ItemRepository', () => {
let itemRepository
let qiitaApiService
before(() => {
qiitaApiService = new QiitaApiService(config)
itemRepository = new ItemRepository(qiitaApiService)
});
describe('#getItemByWord', () => {
let qiitaApiServiceSearchStub
before(() => {
qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search')
qiitaApiServiceSearchStub.resolves({ result: 'success' })
});
after(() => {
qiitaApiServiceSearchStub.restore()
});
it('be fulfilled', (done) => {
expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled
.then((result) => {
expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99)
expect(result).to.eql({ result: 'success' })
})
.then(done, done)
})
})
})
テスト対象のインスタンス
の組み立て
(必要に応じてテスト用の
ものと差し替え)
// ...
describe('ItemRepository', () => {
let itemRepository
let qiitaApiService
before(() => {
qiitaApiService = new QiitaApiService(config)
itemRepository = new ItemRepository(qiitaApiService)
});
describe('#getItemByWord', () => {
let qiitaApiServiceSearchStub
before(() => {
qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search')
qiitaApiServiceSearchStub.resolves({ result: 'success' })
});
after(() => {
qiitaApiServiceSearchStub.restore()
});
it('be fulfilled', (done) => {
expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled
.then((result) => {
expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99)
expect(result).to.eql({ result: 'success' })
})
.then(done, done)
})
})
})
必要に応じてスタブを用意
ほか
■ 静的解析
・ESLint を利用
・Airbnb の規約がおすすめ
・WebStorm と連携しておく
・JSDoc 漏れを検査させるとよい
■ ドキュメント生成
・ESDoc を利用
・テストコードとも連動できる
■ HTTP通信ライブラリ
・axios .. Promise に対応
まとめ
■ ES2015で普通にクラスベースのオブジェ
クト志向でアプリケーションが書ける
ようになった
■ IDE(WebStorm)でクラス含む型のサポート
もある程度うけられる
⇒ 機能はできるだけ class で表現する
.. ちゃんとやるなら TypeScript がいいと思う
Sample code
hkusu/react-app-example
※React 周りのコードも含んじゃってます
END

Contenu connexe

Tendances

はじめよう Backbone.js
はじめよう Backbone.jsはじめよう Backbone.js
はじめよう Backbone.jsHiroki Toyokawa
 
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門Kazunori Tatsuki
 
最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!Yuji Nojima
 
Deep dive into oss written in swift
Deep dive into oss written in swiftDeep dive into oss written in swift
Deep dive into oss written in swiftYuki Asai
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングTanUkkii
 
JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介Yusuke Hirao
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScriptsohta
 
Ruby Sapporo Night Vol.4
Ruby Sapporo Night Vol.4Ruby Sapporo Night Vol.4
Ruby Sapporo Night Vol.4Koji SHIMADA
 
クライアントサイドjavascript簡単紹介
クライアントサイドjavascript簡単紹介クライアントサイドjavascript簡単紹介
クライアントサイドjavascript簡単紹介しくみ製作所
 
第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまで第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまでMugen Fujii
 
React+TypeScriptもいいぞ
React+TypeScriptもいいぞReact+TypeScriptもいいぞ
React+TypeScriptもいいぞMitsuru Ogawa
 
JavaScript基礎勉強会
JavaScript基礎勉強会JavaScript基礎勉強会
JavaScript基礎勉強会大樹 小倉
 
Riot.js と戦った話 (8月26日 oRo LT 会)
Riot.js と戦った話 (8月26日 oRo LT 会)Riot.js と戦った話 (8月26日 oRo LT 会)
Riot.js と戦った話 (8月26日 oRo LT 会)kata shin
 
Deep dive into oss written in swift
Deep dive into oss written in swiftDeep dive into oss written in swift
Deep dive into oss written in swiftYuki Asai
 
Flux with RxSwift
Flux with RxSwiftFlux with RxSwift
Flux with RxSwiftYuji Hato
 
これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6TanUkkii
 
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門spring_raining
 
ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3Masahiro Wakame
 

Tendances (20)

はじめよう Backbone.js
はじめよう Backbone.jsはじめよう Backbone.js
はじめよう Backbone.js
 
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
 
最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!最強オブジェクト指向言語 JavaScript 再入門!
最強オブジェクト指向言語 JavaScript 再入門!
 
Deep dive into oss written in swift
Deep dive into oss written in swiftDeep dive into oss written in swift
Deep dive into oss written in swift
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミング
 
JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介JavaScriptユーティリティライブラリの紹介
JavaScriptユーティリティライブラリの紹介
 
覚醒!JavaScript
覚醒!JavaScript覚醒!JavaScript
覚醒!JavaScript
 
入門ClojureScript
入門ClojureScript入門ClojureScript
入門ClojureScript
 
Ruby Sapporo Night Vol.4
Ruby Sapporo Night Vol.4Ruby Sapporo Night Vol.4
Ruby Sapporo Night Vol.4
 
クライアントサイドjavascript簡単紹介
クライアントサイドjavascript簡単紹介クライアントサイドjavascript簡単紹介
クライアントサイドjavascript簡単紹介
 
第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまで第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまで
 
React+TypeScriptもいいぞ
React+TypeScriptもいいぞReact+TypeScriptもいいぞ
React+TypeScriptもいいぞ
 
JavaScript基礎勉強会
JavaScript基礎勉強会JavaScript基礎勉強会
JavaScript基礎勉強会
 
Riot.js と戦った話 (8月26日 oRo LT 会)
Riot.js と戦った話 (8月26日 oRo LT 会)Riot.js と戦った話 (8月26日 oRo LT 会)
Riot.js と戦った話 (8月26日 oRo LT 会)
 
Rubyize
RubyizeRubyize
Rubyize
 
Deep dive into oss written in swift
Deep dive into oss written in swiftDeep dive into oss written in swift
Deep dive into oss written in swift
 
Flux with RxSwift
Flux with RxSwiftFlux with RxSwift
Flux with RxSwift
 
これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6これからのJavaScriptー関数型プログラミングとECMAScript6
これからのJavaScriptー関数型プログラミングとECMAScript6
 
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門
 
ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3ng-japan 2015 TypeScript+AngularJS 1.3
ng-japan 2015 TypeScript+AngularJS 1.3
 

Similaire à 【YAPC::Asia Hachioji 2016】ES2015のclassでアプリケーションを書いてみた話

New Generation Build System "Fly"
New Generation Build System "Fly"New Generation Build System "Fly"
New Generation Build System "Fly"deepblue will
 
JavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 AutumnJavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 AutumnKoji Ishimoto
 
JavaのGenericsとは?
JavaのGenericsとは?JavaのGenericsとは?
JavaのGenericsとは?Kenji Nakamura
 
JavaScriptおよびXPages Vote技術解説
JavaScriptおよびXPages Vote技術解説JavaScriptおよびXPages Vote技術解説
JavaScriptおよびXPages Vote技術解説賢次 海老原
 
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugSpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugToshiaki Maki
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)Fujio Kojima
 
Spring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframework
Spring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframeworkSpring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframework
Spring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframeworkToshiaki Maki
 
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~decode2016
 
ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用Yatabe Terumasa
 
traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験Toshio Ehara
 
絶対落ちないアプリの作り方
絶対落ちないアプリの作り方絶対落ちないアプリの作り方
絶対落ちないアプリの作り方Fumihiko Shiroyama
 
TDC20111031_Groovy_Geb
TDC20111031_Groovy_GebTDC20111031_Groovy_Geb
TDC20111031_Groovy_GebNobuhiro Sue
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-Kazunari Hara
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」yoshiaki iwanaga
 
WordBench京都12月、WordCampUSからのWP REST APIな話
WordBench京都12月、WordCampUSからのWP REST APIな話WordBench京都12月、WordCampUSからのWP REST APIな話
WordBench京都12月、WordCampUSからのWP REST APIな話Hidetaka Okamoto
 
TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語gypsygypsy
 
サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよkoji lin
 
エンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSエンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSAyumi Goto
 

Similaire à 【YAPC::Asia Hachioji 2016】ES2015のclassでアプリケーションを書いてみた話 (20)

New Generation Build System "Fly"
New Generation Build System "Fly"New Generation Build System "Fly"
New Generation Build System "Fly"
 
JavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 AutumnJavaScript/CSS 2015 Autumn
JavaScript/CSS 2015 Autumn
 
JavaのGenericsとは?
JavaのGenericsとは?JavaのGenericsとは?
JavaのGenericsとは?
 
JavaScriptおよびXPages Vote技術解説
JavaScriptおよびXPages Vote技術解説JavaScriptおよびXPages Vote技術解説
JavaScriptおよびXPages Vote技術解説
 
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsugSpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
SpringOne 2GX 2014 参加報告 & Spring 4.1について #jsug
 
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)「Windows 8 ストア アプリ開発 tips」  hokuriku.net vol.11 (2013年1月26日)
「Windows 8 ストア アプリ開発 tips」 hokuriku.net vol.11 (2013年1月26日)
 
Spring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframework
Spring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframeworkSpring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframework
Spring Frameworkの今 (2013年版) #jjug_ccc #ccc_r17 #springframework
 
20141129-dotNet2015
20141129-dotNet201520141129-dotNet2015
20141129-dotNet2015
 
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
DEV-011_TypeScript ~Any browser. Any host. Any OS. Open Source~
 
ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用
 
traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験traceur-compilerで ECMAScript6を体験
traceur-compilerで ECMAScript6を体験
 
Rx java x retrofit
Rx java x retrofitRx java x retrofit
Rx java x retrofit
 
絶対落ちないアプリの作り方
絶対落ちないアプリの作り方絶対落ちないアプリの作り方
絶対落ちないアプリの作り方
 
TDC20111031_Groovy_Geb
TDC20111031_Groovy_GebTDC20111031_Groovy_Geb
TDC20111031_Groovy_Geb
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
WordBench京都12月、WordCampUSからのWP REST APIな話
WordBench京都12月、WordCampUSからのWP REST APIな話WordBench京都12月、WordCampUSからのWP REST APIな話
WordBench京都12月、WordCampUSからのWP REST APIな話
 
TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語
 
サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよ
 
エンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJSエンタープライズ分野での実践AngularJS
エンタープライズ分野での実践AngularJS
 

Plus de Hiroyuki Kusu

【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する
【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する
【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発するHiroyuki Kusu
 
【Potatotips #30】RxJavaを活用する3つのユースケース
【Potatotips #30】RxJavaを活用する3つのユースケース【Potatotips #30】RxJavaを活用する3つのユースケース
【Potatotips #30】RxJavaを活用する3つのユースケースHiroyuki Kusu
 
【Potatotips #26】Replace EventBus with RxJava/RxAndroid
【Potatotips #26】Replace EventBus with RxJava/RxAndroid【Potatotips #26】Replace EventBus with RxJava/RxAndroid
【Potatotips #26】Replace EventBus with RxJava/RxAndroidHiroyuki Kusu
 
【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する
【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する
【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意するHiroyuki Kusu
 
【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する
【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する
【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲するHiroyuki Kusu
 
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)Hiroyuki Kusu
 
【eLV勉強会】AngularJSでのモバイルフロントエンド開発
【eLV勉強会】AngularJSでのモバイルフロントエンド開発【eLV勉強会】AngularJSでのモバイルフロントエンド開発
【eLV勉強会】AngularJSでのモバイルフロントエンド開発Hiroyuki Kusu
 
エンジニアにMacを薦める理由
エンジニアにMacを薦める理由エンジニアにMacを薦める理由
エンジニアにMacを薦める理由Hiroyuki Kusu
 
ソーシャルアプリで人を熱中させる要素を説明する一枚絵
ソーシャルアプリで人を熱中させる要素を説明する一枚絵ソーシャルアプリで人を熱中させる要素を説明する一枚絵
ソーシャルアプリで人を熱中させる要素を説明する一枚絵Hiroyuki Kusu
 
【ABC2014Spring LT】AngularJSでWEBアプリ開発
【ABC2014Spring LT】AngularJSでWEBアプリ開発【ABC2014Spring LT】AngularJSでWEBアプリ開発
【ABC2014Spring LT】AngularJSでWEBアプリ開発Hiroyuki Kusu
 

Plus de Hiroyuki Kusu (10)

【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する
【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する
【東京Node学園祭2016】Node.js × Babel で AWS Lambda アプリケーションを開発する
 
【Potatotips #30】RxJavaを活用する3つのユースケース
【Potatotips #30】RxJavaを活用する3つのユースケース【Potatotips #30】RxJavaを活用する3つのユースケース
【Potatotips #30】RxJavaを活用する3つのユースケース
 
【Potatotips #26】Replace EventBus with RxJava/RxAndroid
【Potatotips #26】Replace EventBus with RxJava/RxAndroid【Potatotips #26】Replace EventBus with RxJava/RxAndroid
【Potatotips #26】Replace EventBus with RxJava/RxAndroid
 
【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する
【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する
【Potatotips #23】手軽にHTTPでJSONにアクセスできる環境を用意する
 
【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する
【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する
【Roppongi.aar #1】Activity/FragmentからControllerへ処理を委譲する
 
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
【DroidKaigi2015】初学者に嬉しいAndroid開発環境(あとMVCとか)
 
【eLV勉強会】AngularJSでのモバイルフロントエンド開発
【eLV勉強会】AngularJSでのモバイルフロントエンド開発【eLV勉強会】AngularJSでのモバイルフロントエンド開発
【eLV勉強会】AngularJSでのモバイルフロントエンド開発
 
エンジニアにMacを薦める理由
エンジニアにMacを薦める理由エンジニアにMacを薦める理由
エンジニアにMacを薦める理由
 
ソーシャルアプリで人を熱中させる要素を説明する一枚絵
ソーシャルアプリで人を熱中させる要素を説明する一枚絵ソーシャルアプリで人を熱中させる要素を説明する一枚絵
ソーシャルアプリで人を熱中させる要素を説明する一枚絵
 
【ABC2014Spring LT】AngularJSでWEBアプリ開発
【ABC2014Spring LT】AngularJSでWEBアプリ開発【ABC2014Spring LT】AngularJSでWEBアプリ開発
【ABC2014Spring LT】AngularJSでWEBアプリ開発
 

Dernier

20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdf20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdfAyachika Kitazaki
 
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)ssuser539845
 
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-LoopへTetsuya Nihonmatsu
 
2024 01 Virtual_Counselor
2024 01 Virtual_Counselor 2024 01 Virtual_Counselor
2024 01 Virtual_Counselor arts yokohama
 
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~arts yokohama
 
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見Shumpei Kishi
 
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdfTaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdfMatsushita Laboratory
 
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法ssuser370dd7
 

Dernier (11)

20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdf20240326_IoTLT_vol109_kitazaki_v1___.pdf
20240326_IoTLT_vol109_kitazaki_v1___.pdf
 
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
IFIP IP3での資格制度を対象とする国際認定(IPSJ86全国大会シンポジウム)
 
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
「今からでも間に合う」GPTsによる 活用LT会 - 人とAIが協調するHumani-in-the-Loopへ
 
2024 01 Virtual_Counselor
2024 01 Virtual_Counselor 2024 01 Virtual_Counselor
2024 01 Virtual_Counselor
 
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
2024 02 Nihon-Tanken ~Towards a More Inclusive Japan~
 
What is the world where you can make your own semiconductors?
What is the world where you can make your own semiconductors?What is the world where you can make your own semiconductors?
What is the world where you can make your own semiconductors?
 
2024 04 minnanoito
2024 04 minnanoito2024 04 minnanoito
2024 04 minnanoito
 
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
持続可能なDrupal Meetupのコツ - Drupal Meetup Tokyoの知見
 
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdfTaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
TaketoFujikawa_台本中の動作表現に基づくアニメーション原画システムの提案_SIGEC71.pdf
 
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
情報処理学会86回全国大会_Generic OAMをDeep Learning技術によって実現するための課題と解決方法
 
2024 03 CTEA
2024 03 CTEA2024 03 CTEA
2024 03 CTEA
 

【YAPC::Asia Hachioji 2016】ES2015のclassでアプリケーションを書いてみた話

  • 1. ES2015 の class で アプリケーションを 書いてみた話 Hiroyuki Kusu ( @hkusu_ ) YAPC::Asia Hachioji 2016 mid in Shinagawa 7/3 LT
  • 3. ■ 〜2015年12月 ・Android アプリの開発 ■ 2016年1月〜 ・JavaScript アプリケーションの開発 Javaに 慣れ親む
  • 5. ■ ES2015 で書く ・Babel (トランスパイラ) ・Browserify (ブラウザ用の場合) ■ エディタ ・WebStorm (JetBrains 社製 IDE) ・like Android Studio 前提となる環境
  • 7. class Person { constructor(name, age) { this.name = name this.age = age } getName() { return this.name } getAge() { return this.age } hello() { return `こんにちは! ${this.name} さん` } } export default Person Person.js
  • 8. class Person { constructor(name, age) { this.name = name this.age = age } getName() { return this.name } getAge() { return this.age } hello() { return `こんにちは! ${this.name} さん` } } export default Person Person.js コンストラクタ
  • 9. class Person { constructor(name, age) { this.name = name this.age = age } getName() { return this.name } getAge() { return this.age } hello() { return `こんにちは! ${this.name} さん` } } export default Person Person.js インスタンス変数
  • 10. class Person { constructor(name, age) { this.name = name this.age = age } getName() { return this.name } getAge() { return this.age } hello() { return `こんにちは! ${this.name} さん` } } export default Person Person.js インスタンスメソッド
  • 11. class SomeUtil { static isObject(arg) { return typeof arg === 'object' && arg !== null && !Array.isArray(arg); } } export default SomeUtil SomeUtil.js クラスメソッド
  • 12. import Person from './Person' class Men extends Person { hello() { return `おす! ${this.name} さん` } } export default Men Men.js 継承
  • 14. import Person from './Person' import SomeUtil from './SomeUtil' // … const person = new Person('山田', 45) クラスをインポートして利用
  • 16. const Week = { SUN: Symbol(), MON: Symbol(), TUE: Symbol(), WED: Symbol(), THU: Symbol(), FRI: Symbol(), SAT: Symbol(), } export default Week import Week from './Week' // … const myWeek = Week.SUN Week.js 利用例
  • 17. const Action = { SEARCH: Symbol(), REGISTER: Symbol(), UPDATE: Symbol(), DELETE: Symbol(), } export default Action Action.js キーとして利用 (例えば Redux などで)
  • 19. import axios from 'axios' import { config } from './../config/Config' class QiitaApiService { constructor(config) { this.baseUrl = config.QIITA_BASE_URL } search(searchWord, perPage = 10) { return this.httpGet(`search?q=${searchWord}&per_page=${perPage}`) } httpGet(query) { return axios.get(`${this.baseUrl}/${query}`) } } export default QiitaApiService export const qiitaApiService = new QiitaApiService(config) QiitaApiService.js インスタンス化したものを export
  • 20. import { qiitaApiService } from './service/QiitaApiService' // … qiitaApiService.search('JavaScript', 10) .then(() => { // ... }) アプリケーション内で インスタンスが共有される
  • 22. import axios from 'axios' import { config } from './../config/Config' class QiitaApiService { constructor(config) { /** @private */ this.baseUrl = config.QIITA_BASE_URL } search(searchWord, perPage = 10) { return this.httpGet(`search?q=${searchWord}&per_page=${perPage}`) } /** * @private */ httpGet(query) { return axios.get(`${this.baseUrl}/${query}`) } } // … QiitaApiService.js private変数 privateメソッド
  • 25. // … class QiitaApiService { /** * @constructor * @param {Config|SpecConfig} config */ constructor(config) { /** @private */ this.baseUrl = config.QIITA_BASE_URL } /** * @param {string} searchWord * @param {number} [perPage=10] * @returns {promise} */ search(searchWord, perPage = 10) { return this.httpGet(`search?q=${searchWord}&per_page=${perPage}`) } /** * @param {string} query * @returns {promise} * @private */ httpGet(query) { return axios.get(`${this.baseUrl}/${query}`) } } // …
  • 27. /** @type {QiitaApiService} */ export const qiitaApiService = new QiitaApiService(config) 型が迷子になったら @type で指定
  • 28. Test
  • 29. Repository層 Service層 Dependency injection Config 利用 利用 利用 クラス内で出来るだけ別クラスを new() しない static な状態の保持は可能な限り避ける
  • 30. import { config } from './../config/Config' import ItemRepository from './../repository/ItemRepository' import QiitaApiService from './../service/QiitaApiService' const itemRepository = new ItemRepository(new QiitaApiService(config)) Dependency injection
  • 31. // ... describe('ItemRepository', () => { let itemRepository let qiitaApiService before(() => { qiitaApiService = new QiitaApiService(config) itemRepository = new ItemRepository(qiitaApiService) }); describe('#getItemByWord', () => { let qiitaApiServiceSearchStub before(() => { qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search') qiitaApiServiceSearchStub.resolves({ result: 'success' }) }); after(() => { qiitaApiServiceSearchStub.restore() }); it('be fulfilled', (done) => { expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled .then((result) => { expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99) expect(result).to.eql({ result: 'success' }) }) .then(done, done) }) }) }) ※Mocha、Chai、Sinon.JS および Promise系のライブラリを利用 class 単位 でテスト
  • 32. // ... describe('ItemRepository', () => { let itemRepository let qiitaApiService before(() => { qiitaApiService = new QiitaApiService(config) itemRepository = new ItemRepository(qiitaApiService) }); describe('#getItemByWord', () => { let qiitaApiServiceSearchStub before(() => { qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search') qiitaApiServiceSearchStub.resolves({ result: 'success' }) }); after(() => { qiitaApiServiceSearchStub.restore() }); it('be fulfilled', (done) => { expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled .then((result) => { expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99) expect(result).to.eql({ result: 'success' }) }) .then(done, done) }) }) }) メソッドの テスト
  • 33. // ... describe('ItemRepository', () => { let itemRepository let qiitaApiService before(() => { qiitaApiService = new QiitaApiService(config) itemRepository = new ItemRepository(qiitaApiService) }); describe('#getItemByWord', () => { let qiitaApiServiceSearchStub before(() => { qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search') qiitaApiServiceSearchStub.resolves({ result: 'success' }) }); after(() => { qiitaApiServiceSearchStub.restore() }); it('be fulfilled', (done) => { expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled .then((result) => { expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99) expect(result).to.eql({ result: 'success' }) }) .then(done, done) }) }) }) テスト対象のインスタンス の組み立て (必要に応じてテスト用の ものと差し替え)
  • 34. // ... describe('ItemRepository', () => { let itemRepository let qiitaApiService before(() => { qiitaApiService = new QiitaApiService(config) itemRepository = new ItemRepository(qiitaApiService) }); describe('#getItemByWord', () => { let qiitaApiServiceSearchStub before(() => { qiitaApiServiceSearchStub = sinon.stub(qiitaApiService, 'search') qiitaApiServiceSearchStub.resolves({ result: 'success' }) }); after(() => { qiitaApiServiceSearchStub.restore() }); it('be fulfilled', (done) => { expect(itemRepository.getItemByWord('abc', 99)).to.be.fulfilled .then((result) => { expect(qiitaApiServiceSearchStub).to.have.been.calledWith('abc', 99) expect(result).to.eql({ result: 'success' }) }) .then(done, done) }) }) }) 必要に応じてスタブを用意
  • 36. ■ 静的解析 ・ESLint を利用 ・Airbnb の規約がおすすめ ・WebStorm と連携しておく ・JSDoc 漏れを検査させるとよい ■ ドキュメント生成 ・ESDoc を利用 ・テストコードとも連動できる ■ HTTP通信ライブラリ ・axios .. Promise に対応
  • 40. END