Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
関数型プログラミングの考え方を取り入れて予測しやすいコードを書く
Search
ken7253
October 02, 2023
Programming
230
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
関数型プログラミングの考え方を取り入れて予測しやすいコードを書く
社内LT会にて発表した資料です。
ken7253
October 02, 2023
More Decks by ken7253
See All by ken7253
Firefoxにコントリビューションして得られた学び
ken7253
2
180
バンドルサイズを半減させた話 @Browser and UI #3
ken7253
0
84
CSS polyfill とその未来
ken7253
0
290
Browser and UI #2 HTML/ARIA
ken7253
2
360
PEPCは何を変えようとしていたのか
ken7253
3
580
Browser and UI #1 CSS
ken7253
0
180
レビューのやり方を(ちょっと)整理した話
ken7253
1
610
オーバーロード関数の話 @Mita.ts #2
ken7253
0
180
フロントエンドカンファレンス北海道参加レポート
ken7253
0
97
Other Decks in Programming
See All in Programming
<title><a id="</title>君はこのHTMLをパースできるか"></a></title> #雑LT_study
pizzacat83
0
130
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
160
Android CLI
fornewid
0
210
React本体のコードリーディング
high_g_engineer
1
130
yield再入門 #phpcon
o0h
PRO
0
930
Lean は証明の正しさを確認するためだけのツールって思ってませんか?
inoueasei
1
140
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
650
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
130
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.2k
使用 Meilisearch 建立新聞搜尋工具
johnroyer
0
210
ITヒヤリハットを整理してみた ~ライフサイクルと原因から考える再発防止策~
koukimiura
1
140
ソフトウェア設計に溶けるインフラ ― AWS CDK のインフラ認識論
konokenj
3
750
Featured
See All Featured
RailsConf 2023
tenderlove
30
1.5k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
510
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.5k
Designing Experiences People Love
moore
143
24k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
420
Designing for humans not robots
tammielis
254
26k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.7k
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
270
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
200
Transcript
Introduction Functional Programming 関数型プログラミングの考え方を取り入れて予測しやすいコードを書く
ken7253 Frontend developer 技術記事を書いたりするのが趣味。 最近はNext.jsを使ったアプリケーションを書いています。 インターフェイス設計やアクセシビリティ・SSG関連の技術に興味があります。 https://github.com/ken7253 https://zenn.dev/ken7253 https://dairoku-studio.com
前日譚 「なっとく!関数型プログラミング」 という本を買って読んでいました。 参考になる内容が多かった 関数型の考え方を紹介 ガチガチの関数型は難しいけど 少し取り入れてコードの品質を上げる
関数型プログラミングの考え方を部分的に採用し フロントエンドでも馴染み深いライブラリといえば?
None
話すこと 純粋関数について シグニチャーを意識して関数を作る
純粋関数
関数の分類の一つで特に関数型プログラミングで重要な考え方 下記の条件を全て満たした関数のことを純粋関数と呼ぶ 引数のみを利用する 戻り値は常に一つだけ 既存の変数を変更しない 純粋関数とはなにか
「引数のみを利用する」とは下記のようなこと グローバル変数を参照したり、時刻に依存するコードなど。 純粋関数の条件 // 🙆♂ 純粋関数 const pureFunc = (x:number,
y:number): number => { return x * y; }; // 🙅♂ 純粋関数ではない let x = 0; let y = 0; const notPureFunc = (): number => { return x * y; };
戻り値は常に1つだけ。 状況によってエラーを発生させたり、そもそも値を返さない場合がある関数など。 純粋関数の条件 // 🙅♂ 純粋関数ではない const notPureFunc = (a:
number): number | void => { if (a === 0) { throw new Error('Error'); } else if (a >= 100) { return a } // 値を返さない場合もある }
既存の変数を変更しない Array#push() や Array#reverse() などのメソッド、 var / let に対する再代入 などを関数の内部で呼び出して、既存の値を変更している場合など
純粋関数の条件 let num = 0; // 🙆♂ 純粋関数 const pureFunc = (n:number): number => { return n + 1; }; pureFunc(num); // num => 0 let num = 0; // 🙅♂ 純粋関数ではない const notPureFunc = (n:number): number => { return n++; }; notPureFunc(num); // num => 1
テストしやすい 意図しない挙動を起こしづらい コードの挙動が予測しやすい 副作用を分離することは 「臭いものに蓋をする」 だけに見える。 実際は、処理同士の繋がりが 型によって可視化 されてわかりやすいコードになる。 純粋関数だと何が嬉しいか
シグニチャー
シグニチャーとはなにか シグニチャー(シグネチャ)とは下記の情報をまとめた呼称 関数名 引数の型 返り値の型
下記のような関数があるとする。 この状態で何をしている関数であるか理解できる人は少ない。 シグニチャーの情報が少ない場合 export const foo: (a: any, b: any):
any => { // 外部からは見えない何らかの処理 }
シグニチャーをより正確にしてみる これにテストを追加してみる。 こうすることで(テストが無くても)ある程度挙動が推測できる。 シグニチャーの情報が少ない場合 export const sum = (first: number,
second: number): number | TypeError => { // 外部からは見えない何らかの処理 } import { sum } from "./sum" describe('与えられた引数を足し算して返却するsum関数', () => { test('自然数同士の足し算が正しく実行されること', () => {/* 省略 */}) test('引数のどちらかにNaNが渡された場合TypeErrorを返却すること', () => {/* 省略 */}) test('引数のどちらかにInfinityが渡された場合TypeErrorを返却すること', () => {/* 省略 */}) })
例としてこの関数を実際に使ってみる。 このようにシグニチャーから関数の使い方が理解できる。 情報の多い関数は適切に使用できる import { sum } from "./sum"; import
{ sendError } from "./sendError"; const [x,y] = [10, 20]; const sumResult = sum(x,y); // number | TypeError // そのままだと型が合わないので型ガードを利用する。 if (sumResult instanceof TypeError) { // sendError = (error: Error) => void; sendError(sumResult); // sendError(); はエラー情報をサーバーに送る処理として考える } else { console.log(sumResult); }
具体的なコードで見てみる 複数の要素の中から一番高さを持つ要素を探してコンソールに出力する処理 一つの関数にいろいろやらせている例 このようなコードがあった場合、次のように変えてみる。 // 入出力の情報がないので説明のための関数名が長くなりがち const displayHighestElementByElementList = ()
=> { // 要素の取得 const elements = document.querySelectorAll('.some-class'); const elementList = Array.from(elements); // 比較とソート const sortedFromClientHeight = [...elementList].sort((prev, next) => { return next.clientHeight - prev.clientHeight; }); // コンソールへの出力 console.log(sortedFromClientHeight[0]); }; displayHighestElementByElementList();
具体的なコードで見てみる 複数の要素の中から一番高さを持つ要素を探してコンソールに出力する処理 要素の取得 -> 比較関数 -> 出力 という値の流れが掴みやすい。 入出力の型情報があることで挙動が推測しやすい関数になる。 //
与えられた要素の配列から一番高さを持つ要素を返す関数 const getHighestElement = (elementList: Element[]): Element => { const sorted = [...elementList].sort((prev, next) => { return next.clientHeight - prev.clientHeight }); return sorted[0]; }; // 要素の取得 const elementList = Array.from(document.querySelectorAll('.some-class')); // コンソールへの出力 console.log(getHighestElement(elementList));
具体的なコードで見てみる 複数の要素の中から一番高さを持つ要素を探してコンソールに出力する処理 もっと関数型っぽい書き方だとこう。 配列のメソッドをうまく使って無駄なく宣言的に記述する。 // 与えられた要素の配列から一番高さを持つ要素を返す関数 const getHighestElement = (elementList:
Element[]): Element => elementList.reduce((acc, current) => acc.clientHeight >= current.clientHeight ? acc : current ); // 要素の取得 const elementList = Array.from(document.querySelectorAll(".some-class")); // コンソールへの出力 console.log(getHighestElement(elementList));
まとめ 関数を設計するときにいくつか持つとよい視点がある。 純粋関数という視点を持つ 関数の設計を行う場合はシグニチャーに情報を持たせる