👷‍♂️

バグを減らす第一歩は、ちゃんと名前を呼んであげること(名前付き引数を使おう)

2022/05/29に公開

複数人の前で、誰かに何かをお願いするとき、ちゃんと名前呼んでますか?

例えば、体格が普通の人(Aさん)と、マッチョな人(Bさん)が2人、目の前にいるとします。
体格が普通の人
体格が普通のAさん
マッチョな人
マッチョなBさん
「10kgの箱と20kgの箱を持ってきてください」と2人の目の前で頼みます。
誰がどちらの箱を持ってくると楽でしょうか?

  • Aさんが20kgの箱を、Bさんが10kgの箱を持ってくる・・・マッチョな人軽い方を持っている
  • Aさんが10kgの箱を、Bさんが20kgの箱を持ってくる・・・マッチョな人重い方を持っている

マッチョな人が重い方を持ってきたほうが、効率が良さそうですよね!?
ですが、両者が全く話し合わずに、適当にそれぞれの箱をもってこようとすると、非効率な持ち運びになってしまいそうです。

どのように頼めば良さそうか?

「(体格が普通の)Aさんは10kgの、(マッチョな)Bさんは20kgの箱を持ってきてください」

このように頼めば、適切に動いてくれそうです。
「10kgの箱と20kgの箱を持ってきてください」とのお願いと何が異なっているでしょうか..?

それではプログラミングの世界でこのような事例を見ていきましょう

主にKotlinを用いて説明していきます🙏

こんな場合は注意(名前付き引数を使わない場合)

sample.kt
  // 人について出力する
  fun printPerson(
    name: String,
    age: Int,
    country: String,
    height: Int,
    weight: Int,
    phoneNumber: String,
    address: String,
    footSize: Int
  ) { 
    println("名前は${name}で年齢は${age}で出身は${country}で身長は${height}で....略")
  }
  printPerson("kenpi", 2, "Japan", 180, 70, "0000-0000-0000", "Tokyo,Japan", 28)

出力

名前はkenpiで年齢は2で出身はJapanで身長は180で....略

↓このようなミスによるバグが起きやすい

  // heightとweightを逆に設定してメソッドが実行されると....
  printPerson("kenpi", 2, "Japan", 70, 180, "0000-0000-0000", "Tokyo,Japan", 28)

出力(身長と体重の値が逆になってしまっている)

名前はkenpiで年齢は2で出身はJapanで身長は70で....略

解決法 → 名前付き引数を使う

*説明のため引数の数を削減した簡単な例を用います

kotlin

hoge.kt
  // printWord関数
  fun printWord(word: String, num: Int){
    println("言葉${word}と数字${num}")
  }
  // 呼び出し
  printWord(word = "ハロー", num = 20)
  // 呼び出し(引数の順番を変更しても引数名が同じ引数に値が代入される)
  printWord(num = 20, word = "ハロー")

出力

言葉ハローと数字20

TypeScriptではこうなる

Kotlinと同じ静的型付き言語であるTypeScriptではどうなるのでしょうか?
調べたところ下記のような形で実現することができました。

hoge.ts
//3 引数の型定義
type ArgumentType = {
  word: string,
  num: number
}
//2 printWord関数
const printWord = ({word, num}: ArgumentType ) => {
  console.log(`言葉:${word}と数字:${num}`);
}
//1 呼び出し
printWord({word: 'ハロー', num: 20});
printWord({num: 20, word: 'ハロー'});

上記コードを3箇所に分類します

  1. 呼び出し
printWord({word: 'ハロー', num: 20});
printWord({num: 20, word: 'ハロー'});

通常の引数の形はprintword('ハロー',20)と、値だけを渡す形になります。

一方今回のように名前をつけたい場合は引数部分を{key: value}形式で渡す形になります。

  1. printWord関数
const printWord = ({word, num}: ArgumentType ) => {
  console.log(`言葉:${word}と数字:${num}`);
}

通常の引数の形はprintword = (word: string, num: number)と、値とその型を定義する形になります。

一方今回のように名前をつけたい場合は引数部分を{key1,key2}形式で定義する形になります。
この形式だと、型を書くことができず、引数の型がany型となってしまい、TypeScriptの恩恵を最大限受けることができない形になってしまいます。

  1. Typeを定義して引数がany型になるのを避ける
type ArgumentType = {
  word: string,
  num: number
}

// 関数の引数に型を付与する 
({word, num}: ArgumentType )

以上でTypeScriptでも名前付き引数のような挙動を実現することができます。

比較

KotlinとTypeScriptを比較すると、個人的には、引数に
hoge(word = 'hoge')
と代入形式のような見た目で書くことができるKotlinのほうが好みです。
TypeScriptの方は
hoge({word: 'hoge'})
とオブジェクトの見た目で渡してあげる必要があり、少し読み解くのに時間がかかってしまいそうでした。

名前付き引数を使って安全なコーディングを!

Discussion