4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

クリーンコード

Posted at

クリーンコードの原則

  • 他人が読みやすい
  • コードの意味がわかりやすく、文章のように意味が伝わる。
  • 読んでいて疲れない
  • 変数、関数、クラス名が適切な名前
  • 無駄な部分まで読む必要がない
  • バグが混入しにくい
  • 改修箇所が限定される
  • 改修による既存コードへの影響が限定される
  • 新規機能を追加しやすい
  • 冗長な記述がない
  • テストがしやすい
  • コードの流れに一連の文脈が存在する

命名規則

# bad
const a = 300 / 60;

# good
const mintutes = 300;
const hours = minutes /60;
# bad
function calc(number) {
  return number / 60;
}

# good
function convertMinutesToHours(minutes) {
  return minutes / 60;
}

良い変数名

  • 変数が保持するものを正確に説明
  • 曖昧でなく明確に説明
  • 短すぎず、長すぎないように
  • 多くに人に意味がわかる
  • 発音可能

識別子とケース

識別子:変数名、関数名、クラス名などの識別するためのもの

  • ケバブケース
    kebabu-case
  • スネークケース
    snake_case
  • アッパースネークケース(コンスタントケース)
    UPPER_SNAKE_CASE
  • パスカルケース
    PascalCase
  • キャメルケース
    camelCase

審議値の変数名

  • is〜
    isEmpty, isSet
  • 過去分詞系
    done, finished, sent, put

変数名の接頭語

  • get〜:値を返す、取得する
    getInteger
  • set〜:値を設定する
    setName
  • is〜:真偽値を返す
    isEmpty
  • has〜:持っているか
    hasPosts
  • needs〜:必要か
  • can:〜できるか
    canStartTime
  • should:〜すべきか

** isExistsなど動詞が連続するような命名は避けて、Existsなど三人称をつける対応。
https://qiita.com/yskszk/items/5a7f99c974773f03a82a

変数名、プロパティ:(形容詞+)名詞

  • themeColor
  • customerType
  • serviceName

関数、メソッド:動詞(+形容詞+名詞)

  • getNumbers
  • getUserName
  • addActiveButton

クラス:(形容詞+)名詞

  • Animals
  • ScoreCounter
  • PurchaseHistory

配列の末尾には複数名のsをつける

# bad
user.forEach
#good
users.forEach

# bad
animal.map
animals.map

ウソの変数名をつけない

# bad
# 配列ではなく、オブジェクトであり、リストでもないので誤った印象を与える。Listは配列の印象を与える。
const averageList = {
  japanese: 30,
  math: 10,
  English: 30
}

# good
const AVERAGE_SCORE = {
  japanese: 30,
  math: 10,
  English: 30
}

AVERAGE_SCORE.japaneseのように参照するので、その辺りも意識すると良い。値の保持ならキャメルケースでも良いかも。ただ、constであってもオブジェクトのプロパティは更新可能なので、定数化しても良いかもしれない。

同じ意味合いの単語は統一すること

以下は類似単語の例

start, begin
stop, end
modify, update, change
create, new, factory
find, search
done, finish, complete
deliver, dispatch, send
select, choose
show, display

反対の意味を持つ値は対比の名前をつける

prev/next
first/last
create/delete
source/destination
add/remove
show/hide
min/max
public/private
success/failure

意味のない単語を含めない

Stringいらない
personNameString

DataInfoはなくてもいい。
UserDataUserInfo

あと個人的に気になるのが、
usersListのように複数形にListをつける形。usersだけで十分意味は伝わるのでListは不要。

変数名を省略するコツ

a11y: accessibility
i18n: internationalization
init: initialize
calc: calculation
idx: index
cstm: customer
srvc: service
btn: button
_privateMethod, _privateProp(最近は#で表すようになった。)

関数定義

  • 関数は責務を小さく作る
  • 関数内でなるべく条件分岐をかかない
  • 関数はDRYで作成使用
    たまたま共通しているからといって共通しないように、ドメインを意識できると良い。

引数が多いとオブジェクトにまとめる

目安は引数が3以上?

function storeUser(user){
// userの保存処理
}

const user = {
userId: 1,
name: "Tom",
age: 22,
hobby: "soccer",
};

storeUser(user);

引数の設定では論理和よりデフォルト引数を使う

以下は初級者は結構見逃しがちかも。

論理和では`falsy`かどうかが判断基準
引数のデフォルト値は`undefined`かどうかが判断基準

例えば、falsyである0を使うと、
論理和の場合はfalsyとなり、100が設定されてしまう。
一方でデフォルト引数の場合は想定通り0を設定できる。

レアケースかもしれないが、一応頭の片隅には押さえておきたい。

function drawSquare(color, size ){
size = size || 100;
  render('square', size, color);
}

# 0にすると想定通りにならず、100がセットされる。
draqSquare('#fff', 0)

以下のようにデフォルト引数を使用するとundefinedのみセットされるので想定通りとなる。

function drawSquare(color, size = 100 ){
size = size || 100;
  render('square', size, color);
}

drawSquare('#fff')
draqSquare('#fff', 0)

オブジェクトを引数で渡す

これはよく考えると使ったことなかったなー。

function createUser ({age = -1, name= "no name", posts = []} = {} ) => {
  const registerUser = {age, name, posts};
  db.user.create(registerUser);
}

関数は使用順に上から下に書く(垂直フォーマット)

参照透過性

決まった入力(引数)に対して、必ず決まった出力を返す

副作用のない関数を分離することでテストをしやすくなる

渡ってきたオブジェクトの中身を書き換えるのは止める

以下のように引数を変えて返すような記述はだめ。

function sortDesc(itemIds){
  itemIds.sort();
}
const itemIds = [4, 3, 2, 1]
sortDesc(itemIds);

新しい変数を用意してそれに格納する。

function sortDesc(itemIds){
  const newItemIds = [...itemIds]
  newItemIds.sort();
  return newItemIds
}
const itemIds = [4, 3, 2, 1]
const sortedItemIds = sortDesc(itemIds);

# クラス

  • クラスはなるべく小さく作る
class Cart {
  addProduct(){}
  addProductPrice(){}
  addProductCoupon(){}
  calculatePrice(){}
  printReceipt(){}
}
class Product {
  getPrice(){}
  getCoupon(){}
}

class Cart {
  add(){}
  calculatePrice(){}
  printReceipt(){}
}

クラスの情報はできる限り隠蔽する

意図しない変更を避けるためにクラス情報はできる限り隠蔽する。

以下の書き方だと外部から呼び出し可能。

  modelNumber = '型番'
   # 以下の書き方でもok.引数を取る場合はconstructorを使うこと。
   constructor(){
    this.modelNumber = '型番'
   }
}

外部からの呼び出しを避けるために、変数の前に#をつける。

  # 以下のように書くとインスタンスを生成しても
  # console.log(television.#modelNumber)のように呼び出せない。
   # #を使う場合、constructorで初期化する場合にも`#hoge`で冒頭で宣言する必要あり。
  #modelNumber = '型番'

  # ただし、クラス内の関数で呼ばれているものについては、外部からでも参照可能。
  displayModelNumber(){
    console.log(television.#modelNumber)
  }

    # 変更や取得もクラス内にメソッドを定義して可能。
    get modelNumber() {
    return this.#modelNumber;
  }

    set modelNumber(modelNumber) {
    this.#modelNumber = modelNumber
  }
}

  # この取得や変更のセッター、ゲッターの場合、以下のような書き方ができる。
  console.log(television.modelNumber) # ゲッター 
  television.modelNumber = '12345' # セッター
4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?