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

How to handle the speed and the quality in ITP team

Hiroaki KARASAWA
November 22, 2019
1k

How to handle the speed and the quality in ITP team

This is the incomplete PDF output of the Web page.
If you want to see the complete slides, please refer this URL ☞ https://karszawa.github.io/bio/slides/how-to-handle-speed-and-quality/dist/index.html

Hiroaki KARASAWA

November 22, 2019
Tweet

Transcript

  1. 自己紹介 
 
 
 Hiroaki
KARASAWA 
 @karszawa 
 Mercari,
Web Frontend

    Engineer
(2019 新卒) 
 React,
TypeScript,
GraphQL,
ReactNative(Expo)
  2. 学生時代 明石高専
 ☞
 東京大学EEIC (編入)☞
 学士(工学) メルカリ
/
LINE
/
 クックパッド
 など5 社でインターン

    JPHacks
 などのハッカソンに参加 卒業研究で管理栄養士とアスリート向けのサービスを開発
  3. Web アプリケーションとしてのITP React / Redux / Redux-Saga による SPA WebView

    上でのみ表示される特殊なアプリケーション 開発はシミュレータではなくPC のブラウザで (最終確認はシミュレータだが、シミュレータは操作しにくくデバッグしにくいので使わない)
  4. ITP は単一のアプリケーションだが巨大で複雑なビジネスロジックを持っている ITP (取引画面)は次の条件で振る舞いを変える 購入者 
 か
 出品者 取引状態 
(WaitShipping
/
WaitReview
/
Done,
...)

    発送方法 
( らくらくメルカリ便,
 ゆうゆうメルカリ便,
 大型らくらくメルカリ便,
...) 商品カテゴリ 
( あんしんスマホサポート,
 あんしん自動車保証,
...)
  5. Presentation Layer (React) マークアップやスタイリング 責務が明確なのでデザインシステムに移行しやすい(移行したとは言っていない) const const
CommentBoxTypeOne 
CommentBoxTypeOne: :
React 
React.

    .FC FC< <Props Props> >
 
= =
 
( ({ {
 
 

messages 

messages, ,
 
 

handleMessageChange 

handleMessageChange, ,
 
 

handleSubmit 

handleSubmit, ,
 
 

shouldDisableSendButton 

shouldDisableSendButton, ,
 
 } }) )
 
=> =>
 
( (
 
 

 

< <div
 div
class class= ="block" "block"> >
 
 



 



< <textarea textarea
 
 





value 





value= ={ {message message} }
 
 





onChange 





onChange= ={ {handleMessageChange handleMessageChange} }
 
 



 



/ /> >
 
 



 



{ {! !shouldDisableSendButton
 shouldDisableSendButton
&& &&
 
< <PrimaryButton
onClick PrimaryButton
onClick= ={ {handleSubmit handleSubmit} }
 
/ /> >} }
 
 

 

< </ /div div> >
 
 ) ); ;
 

  6. Presentaion Layer (React-Redux) コンポーネント・データを選択し紐付ける const const
CommentBox 
CommentBox: :
React 
React. .FC

    FC< <Props Props> >
 
= =
 
( ({ {
 
 

shouldDisableSentButton 

shouldDisableSentButton, ,
 
 

messages 

messages, ,
 
 } }) )
 
=> =>
 
{ {
 
 

 

if if
 
( (someBranchingLogic someBranchingLogic) )
 
{ {
 
 



 



return return
 
< <CommentBoxTypeOne
 CommentBoxTypeOne
/ /> >; ;
 
 

 

} }
 
 

 

return return
 
< <CommentBoxTypeTwo
 CommentBoxTypeTwo
/ /> >; ;
 
 } }
 
 
 
 const const
 
mapStateToProps mapStateToProps
 
= =
 
( ({ {
transaction
 
transaction
} }: :
Store 
Store) )
 
=> =>
 
( ({ {
 
 

 

//
...some
display
logic //
...some
display
logic
 
 

shouldDisableSentButton 

shouldDisableSentButton, ,
 
 

messages 

messages: :
 
someCalculation someCalculation( (transaction transaction. .messages messages) ), ,
 
 } }) ); ;; ;
 
 
 
 const const
 
mapDispatchToProps mapDispatchToProps
 
= =
 
( () )
 
=> =>
 
( ({ {
 
 

handleMessageChange 

handleMessageChange: :
updateMessage 
updateMessage
 
 } }) ); ;
 
 
 

  7. Business Logic Layer (Redux-Saga) 振る舞いを定義する層 例:
 メッセージを送信するときのビジネスロジック
 
 1.
 コメントボックスに入力されたメッセージを取り出す


    2.
 本当に送信するかの確認のためにダイアログを表示する
 3.
 確認ボタンが押されたらメッセージをAPI に送信する
 4.
API にエラーが発生したらエラーメッセージを表示する
 5.
 送信に成功したらメッセージのリストを更新する

  8. Business Logic layer (Redux-Saga) Saga を起動 function function
 
createRootSaga createRootSaga(

    (api api: :
APIClient 
APIClient) )
 
{ {
 
 

 

return return
 
function function
 
* *rootSaga rootSaga( () )
 
{ {
 
 



 



yield yield
 
fork fork( (function function* *( () )
 
{ {
 
 





 





while while( (true true) )
 
{ {
 
 







 







const const
action
 
action
= =
 
yield yield
 
take take( (POST_CHAT_MESSAGE POST_CHAT_MESSAGE) ); ;
 
 







 







yield yield
 
call call( (postMessageSaga postMessageSaga, ,
apiClient 
apiClient, ,
action 
action) ); ;
 
 





 





} }
 
 



 



} }) ); ;
 
 

 

} }
 
 } }
 

  9. Business Logic layer (Redux-Saga) Saga 本体 export export
 
function function*

    *
 
postMessageSaga postMessageSaga( (api api: :
APIClient 
APIClient, ,
action 
action: :
ReduxAction 
ReduxAction< <{ {
message 
message: :
 
 

 

//
1.
 コメントボックスに入力されたメッセージを取り出す //
1.
 コメントボックスに入力されたメッセージを取り出す 
 
 

 

const const
 
{ {
message
 
message
} }
 
= =
action 
action. .payload payload; ;
 
 
 
 

 

//
2.
 本当に送信するかの確認のためにダイアログを表示する //
2.
 本当に送信するかの確認のためにダイアログを表示する 
 
 

 

const const
confirmParams 
confirmParams: :
ConfirmParams
 
ConfirmParams
= =
 
{ {
 
 



message 



message: :
 
" 本当にメッセージを送信しますか?" " 本当にメッセージを送信しますか?", ,
 
 



confirmText 



confirmText: :
 
" はい" " はい", ,
 
 



dismissText 



dismissText: :
 
" いいえ" " いいえ"
 
 

 

} }; ;
 
 

 

if if
 
( (! !( (yield yield
 
call call( (nativeConfirm nativeConfirm, ,
confirmParams 
confirmParams) )) )) )
 
{ {
 
 



 



return return; ;
 
 

 

} }
 
 
 
 

 

const const
evidenceId
 
evidenceId
= =
 
yield yield
 
select select( (transactionEvidenceSelector transactionEvidenceSelector) ); ;
 
 
 
 

 

try try
 
{ {
 
 



 



//
3.
 確認ボタンが押されたらメッセージをAPI に送信する //
3.
 確認ボタンが押されたらメッセージをAPI に送信する 
 
 



 



yield yield
 
call call( ([ [api api, ,
api 
api. .postTransactionmessage postTransactionmessage] ], ,
 
{ {
evidenceId 
evidenceId, ,
message
 
message
} }) ); ;
 
 

 

} }
 
catch catch( (e e) )
 
{ {
 

  10. Data Layer (Redux Store) Reducer にロジックを書くことは可能 絶対にロジックを持たせない強い意思が重要 function function
 
comment

    comment( (state state: :
string
 
string
= =
 
"" "", ,
action 
action: :
ReduxAction 
ReduxAction< <Comment Comment> >) )
 
{ {
 
 

 

switch switch
 
( (action action. .type type) )
 
{ {
 
 



 



case case
 
INPUT_COMMENT INPUT_COMMENT: :
 
 





 





return return
action 
action. .payload payload; ;
 
 



 



case case
 
CLEAR_COMMENT CLEAR_COMMENT: :
 
 





 





return return
 
"" ""; ;
 
 



 



default default: :
 
 





 





return return
state 
state; ;
 
 

 

} }
 
 } }
 

  11. ディレクトリベースでレイヤを分割して分割の間違いが起こりにくいようにしている src
 ├──
common
 │ 
└──
components
→
Common
Presentation
Layer
(Damb
Components)
 │ 




├──
Button.tsx
 │ 




├──
Panel.tsx
 │

    




└──
Row.tsx
 └──
transactions
→
 取引方法ごとにディレクトリを分割
 



├──
car
 



├──
oogata
 



└──
rakuraku
 







├──
Buyer.tsx
 







├──
Seller.tsx
 







├──
components
→
Specific
Presentation
Layer
(Damb
Components)
 







│ 
├──
ProductDetail.tsx
 







│ 
└──
TransactionInfo.tsx
 







├──
containers
→
Presentation
Layer
(Smart
Containers)
 







│ 
├──
Done.tsx
 







│ 
├──
WaitReview.tsx
 







│ 
└──
WaitShipping.tsx
 







└──
stores
 











├──
reducers.ts
→
Data
Layer
 











└──
sagas.ts
→
Logic
Layer

  12. Sprint Planning (1h) タスクをS ・M ・L でざっくり推定 正確な推定は不可能なのでやるだけ無駄 推定が難しい調査系のタスクは「2 人で1

    日」等の人月型タイムボックスで実施 その期間で終わらなければ、他のタスクとの優先度を再度調整 優先度が下がって次のスプリントになることも
  13. まとめ | 話してないこと Re-architecture
 プロジェクト(古いページから新しいページにマイグレートする方法) レイヤごとに選択したテストツール(Jest,Enzyme,Storybook,Storyshots,Cypress ) Redux-Saga のテストが書きやすいという話ともっと書きやすくするための工夫 コードオーナーによる品質の保証とメンバーの教育

    QA との協力的E2E テスト WebView のデザインシステムが難しいという話 最近筋トレを始めた話 開発時におけるバックエンドへの依存を減らすためのモックサーバー 最近そのモックサーバーをon-browser にしようとしている話 WebView 特有のクライアントネイティブAPI のモッキング