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

読みやすいコードの書き方 第 5 回 / Code readability: Session 5 (ver. 2, Ja)

読みやすいコードの書き方 第 5 回 / Code readability: Session 5 (ver. 2, Ja)

第 5 回: 関数

---

セッションリスト

第 1 回: 導入と原則
- https://speakerdeck.com/munetoshi/code-readability-session-1-ver-2-ja

第 2 回: 命名
- https://speakerdeck.com/munetoshi/code-readability-session-2-ver-2-ja

第 3 回: コメント
- https://speakerdeck.com/munetoshi/code-readability-session-3-ver-2-ja

第 4 回: 状態
- https://speakerdeck.com/munetoshi/code-readability-session-4-ver-2-ja

第 5 回: 関数
- https://speakerdeck.com/munetoshi/code-readability-session-5-ver-2-ja

第 6 回: 依存関係 I
- https://speakerdeck.com/munetoshi/code-readability-session-6-ver-2-ja

第 7 回: 依存関係 II
- https://speakerdeck.com/munetoshi/code-readability-session-7-ver-2-ja

第 8 回: レビュー
- https://speakerdeck.com/munetoshi/code-readability-session-8-ver-2-ja

---

関連書籍 「読みやすいコードのガイドライン - 持続可能なソフトウェア開発のために」
- https://gihyo.jp/book/2022/978-4-297-13036-7

英語版のリスト: https://gist.github.com/munetoshi/65a1b563fb2c271f328c121a4ac63571#file-code-readability-links-md

以前のバージョン (英語): https://speakerdeck.com/munetoshi/code-readability

© 2019-2023 Munetoshi Ishikawa, supported by LINE corporation

Munetoshi Ishikawa

May 11, 2023
Tweet

More Decks by Munetoshi Ishikawa

Other Decks in Programming

Transcript

  1. ߨٛͷߏ੒ - ಋೖͱݪଇ - ࣗવݴޠ: ໋໊, ίϝϯτ - ܕͷߏ଄: ঢ়ଶ,

    ؔ਺ - ܕؒͷߏ଄: ґଘؔ܎I, ґଘؔ܎II - ϨϏϡʔ ؔ਺ > ಋೖ
  2. ͜ͷߨٛʹ͓͚Δʮؔ਺ʯͷൣғ - αϒϧʔνϯ - ϓϩγʔδϟ - ϝιου - ίϯϐϡʔςουϓϩύςΟ -

    ίϯετϥΫλɾΠχγϟϥΠθʔγϣϯϒϩοΫ - ... ؔ਺ > ಋೖ
  3. ࠓճͷ಺༰ ੹೚Λ໌֬ʹ͢Δ - ཁ໿͠ʹ͍ؔ͘਺Λ෼ׂ͢Δ - ίϚϯυͱΫΤϦΛ෼ׂ͢Δ ྲྀΕΛ໌֬ʹ͢Δ - ఆٛࢦ޲ϓϩάϥϛϯάΛߦ͏ -

    ϋοϐʔύεʹয఺Λ౰ͯΔ - ৚݅Ͱͳ͘ɺର৅Ͱ෼ׂ͢Δ ؔ਺ > ੹೚ > ཁ໿ʹΑΔ֬ೝ
  4. ؔ਺ͷཁ໿: ྫ 1/2 ໰୊: ͜ͷίʔυΛͲͷΑ͏ʹཁ໿Ͱ͖Δʁ messageView.text = receivedMessageData.contentText senderNameView.text =

    receivedMessageData.senderName timestampView.text = receivedMessageData.sentTimeText ղ౴ྫ: "ड͚औͬͨϝοηʔδͰදࣔϨΠΞ΢τΛߋ৽͢Δ" ؔ਺ > ੹೚ > ཁ໿ʹΑΔ֬ೝ
  5. ؔ਺ͷཁ໿: ྫ 2/2 ໰୊: ͜ͷίʔυΛͲͷΑ͏ʹཁ໿Ͱ͖Δʁ messageView.text = receivedMessageData.contentText doOnTransaction {

    messageDatabase.insertNewMessage(receivedMessageData) } ճ౴ྫʁ: "ϝοηʔδσʔλΛදࣔͨ͠ ޙʹɺอଘ͢Δ" "ϝοηʔδσʔλΛड͚औͬͨ ࣌ʹɺॲཧΛ͢Δ" ؔ਺ > ੹೚ > ཁ໿ʹΑΔ֬ೝ
  6. ؔ਺ͷ੹೚ͱཁ໿ͷؔ܎ ཁ໿͕ॻ͖ʹ͍͘ = ؔ਺ͷ෼ׂ͕ඞཁ͔΋ fun bindMessageViewData(messageData: MessageData) { ... }

    fun saveMessageDataToDatabase(messageData: MessageData) { ... } ྫ֎: - ଞϨΠϠ/Ϟδϡʔϧʹެ։͞ΕͨΠϯλʔϑΣΠε - ΠϕϯτॲཧͷΤϯτϦʔϙΠϯτ ؔ਺ > ੹೚ > ཁ໿ʹΑΔ֬ೝ
  7. ίϚϯυɾΫΤϦ෼཭ͷݪଇ: ྫ 1/2 class IntList(vararg elements: Int) { infix fun

    append(others: IntList): IntList = ... } val a = IntList(1, 2) val b = IntList(3, 4) val c = a append b ໰୊: a, b, c ͷظ଴͞ΕΔ஋͸ʁ ؔ਺ > ੹೚ > ίϚϯυͱΫΤϦ
  8. ίϚϯυɾΫΤϦ෼཭ͷݪଇ: ྫ 2/2 val a = IntList(1, 2) val b

    = IntList(3, 4) val c = a append b ௨ৗظ଴͞ΕΔ݁Ռ: a={1, 2}, b={3, 4}, c={1, 2, 3, 4} Α͘ͳ͍ಈ࡞ͷ݁Ռ: a={1, 2, 3, 4}, b={3, 4}, c={1, 2, 3, 4} append ؔ਺͸໭Γ஋Λ࣋ͭͷͰ a ΍ b Λมߋ͢΂͖Ͱ͸ͳ͍ ؔ਺ > ੹೚ > ίϚϯυͱΫΤϦ
  9. ίϚϯυɾΫΤϦ෼཭ͷݪଇ: σϝϦοτ 2/3 Α͘ͳ͍ίʔυͷྫ class UserDataStore { private var latestOperationResult:

    Result = NO_OPERATION // Command fun saveUserData(userData: UserData) = ... // Query val wasLatestOperationSuccessful: Boolean get() = ... } latestOperationResult ͕όάͷݪҼʹͳΔ ؔ਺ > ੹೚ > ίϚϯυͱΫΤϦ
  10. ίϚϯυɾΫΤϦ෼཭ͷݪଇ: σϝϦοτ 3/3 Α͍ίʔυͷྫ class UserDataRequester { /** * Saves

    a given user data to ... * Then, returns true if the operation successful, otherwise false. */ fun saveUserData(userData: UserData): Boolean = ... } ࠷ޙͷঢ়ଶΛฦ͢͜ͱͰɺอଘͷඞཁ͕ͳ͘ͳΔ ؔ਺ > ੹೚ > ίϚϯυͱΫΤϦ
  11. ίϚϯυɾΫΤϦͷ෼཭Λ͢Δ৚݅ ʮϝΠϯͷʯ݁ՌΛฦ͢ͱ͖͸มߋ͠ͳ͍ = ʮαϒͷʯ݁ՌΛฦ͢ͱ͖͸มߋΛ൐ͬͯΑ͍ - ϝΠϯͷ݁Ռ: ม׵ɾܭࢉ݁Ռ, ৽͍͠Πϯελϯε ... -

    αϒͷ݁Ռ: Τϥʔ஋, มߋͷϝλσʔλʢετΞͨ͠αΠζʣ... (υΩϡϝϯςʔγϣϯ͕ඞਢ) σϑΝΫτελϯμʔυͱͳ͍ͬͯΔΠϯλʔϑΣΠε΋Մ ྫ: Queue<E>.poll(): E, Iterator<E>.next(): E ؔ਺ > ੹೚ > ίϚϯυͱΫΤϦ
  12. ࠓճͷ಺༰ ੹೚Λ໌֬ʹ͢Δ - ཁ໿͠ʹ͍ؔ͘਺Λ෼ׂ͢Δ - ίϚϯυͱΫΤϦΛ෼ׂ͢Δ ྲྀΕΛ໌֬ʹ͢Δ - ఆٛࢦ޲ϓϩάϥϛϯάΛߦ͏ -

    ϋοϐʔύεʹয఺Λ౰ͯΔ - ৚݅Ͱͳ͘ɺର৅Ͱ෼ׂ͢Δ ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  13. Ҿ਺ͷωετ: मਖ਼ํ๏ ໭Γ஋ʹ ໊લͷ͍ͭͨϩʔΧϧม਺ Λ࢖͏ val userModel = repository.queryUserModel(userId) val

    viewUpdateResult = presenter.updateSelfProfileView(UserModel) showDialogOnError(viewUpdateResult) ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  14. ϥϜμΛ࢖͏ϝιουνΣΠϯ: ໰୊఺ 1/2 ໰୊: ͜ͷίʔυͷಡΈʹ͍͘఺͸ʁ return queryTeamMemberIds(teamId) .map { memberId

    -> ... // Convert to UserModel ... } .filter { val userStatus = ... userStatus.isOnline } .map { it.emailAddress } ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  15. ϥϜμΛ࢖͏ϝιουνΣΠϯ: ໰୊఺ 2/2 ղ౴: ҎԼͷ 2 ͭΛཧղ͠ͳ͍ͱಈ࡞͕Θ͔Βͳ͍ - ֤ϝιουݺͼग़͠ͷϨγʔό (=

    ֤ݺͼग़͠ͷ໭Γ஋) - ϥϜμͷಈ࡞ͷৄࡉ ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  16. ϥϜμΛ࢖͏ϝιουνΣΠϯ: मਖ਼ํ๏ 1/2 Ҋ1: ໊લͷ͍ͭͨϩʔΧϧม਺ ͰνΣΠϯΛ෼ׂ͢Δ val teamMembers = queryTeamMemberIds(teamId).map

    { ... ... } val onlineTeamMembers = teamMembers.filter { ... ... } return onlineTeamMembers.map { it.emailAddress } ϥϜμ͕௕͍ͱɺྲྀΕ͕ಡΈʹ͍͘Մೳੑ΋ ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  17. ϥϜμΛ࢖͏ϝιουνΣΠϯ: मਖ਼ํ๏ 2/2 Ҋ2: ໊લͷ͍ͭͨϓϥΠϕʔτؔ਺ ͰϥϜμΛஔ͖׵͑Δ return queryTeamMemberIds(teamId) .map(::toUserModel) .filter(::isOnline)

    .map { it.emailAddress } ... private fun toUserModel(userId: UserId): UserModel { ... } private fun isOnline(userModel: UserModel): Boolean { ... } ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  18. நग़ͷམͱ݀͠: ΦϦδφϧͷίʔυ val userNameTextView: View = ... val profileImageView: View

    = ... init { // Complex userNameTextView initialization code userNameTextView... // Complex profileImageView initialization code profileImageView... } init ϒϩοΫ͕ංେԽͨͨ͠Ίநग़͢Δ ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  19. நग़ͷམͱ݀͠: ؒҧͬͨमਖ਼ํ๏ var userNameTextView: View? = null var profileImageView: View?

    = null init { initializeUserNameTextView() initializeProfileImageView() } private fun initializeUserNameTextView() { userNameTextView = ... private fun initializeProfileImageView() { profileImageView = ... ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  20. நग़ͷམͱ݀͠: Կ͕ؒҧ͍͔ͬͯͨ - ෆཁͳՄมੑɾnullable - ෳ਺ճ initialize... ͕ݺ͹ΕΔՄೳੑ - ؔ਺໊

    initialize... ͷᐆດੑ நग़͞ΕΔίʔυͷൣғΛ࠷దԽ͢Δ ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  21. நग़ͷམͱ݀͠: ਖ਼͍͠मਖ਼ํ๏ Ϗϡʔͷੜ੒ɾॳظԽ෦෼ͷΈΛநग़͢Δ val userNameTextView: View = createUserNameTextView() val profileImageView:

    View = createProfileImageView() private fun createUserNameTextView(): TextView = ... private fun createProfileImageView(): ImageView = ... ؔ਺ > ྲྀΕ > ఆٛࢦ޲ϓϩάϥϛϯά
  22. ࠓճͷ಺༰ ੹೚Λ໌֬ʹ͢Δ - ཁ໿͠ʹ͍ؔ͘਺Λ෼ׂ͢Δ - ίϚϯυͱΫΤϦΛ෼ׂ͢Δ ྲྀΕΛ໌֬ʹ͢Δ - ఆٛࢦ޲ϓϩάϥϛϯάΛߦ͏ -

    ϋοϐʔύεʹয఺Λ౰ͯΔ - ৚݅Ͱͳ͘ɺର৅Ͱ෼ׂ͢Δ ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  23. ϋοϐʔύεͱΞϯϋοϐʔύε: ྫ String.toIntOrNull() ϋοϐʔύε: ੔਺Λฦ͢ e.g, "-1234", "0", "+001", "-2147483648"

    Ξϯϋοϐʔύε: null Λฦ͢ e.g., "--0", "text", "", "2147483648", "1.0" ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  24. ΞʔϦʔϦλʔϯ: Α͘ͳ͍ྫ if (isNetworkAvailable()) { val queryResult = queryToServer() if

    (queryResult.isValid) { // Do something with queryResult... } else { showInvalidResponseDialog() } } else { showNetworkUnavailableDialog() } ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  25. ΞʔϦʔϦλʔϯ: Α͍ྫ if (!isNetworkAvailable()) { showNetworkUnavailableDialog() return } val queryResult

    = queryToServer() if (!queryResult.isValid) { showInvalidResponseDialog() return } // Do something with queryResult... ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  26. ΞʔϦʔϦλʔϯ: ஫ҙ఺ 1/2 when ΍ switch ͷҰ෦ͷ෼ذͰͷϦλʔϯΛආ͚Δ ΞʔϦʔϦλʔϯࣗମ΍ͦͷ৚݅Λݟམͱ͢Մೳੑ͕͋Δ val messageText

    = when (type) { FOO -> "this is FOO" BAR -> "this is BAR" null -> return } ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  27. ΞʔϦʔϦλʔϯ: ஫ҙ఺ 1/2 when ΍ switch ͷҰ෦ͷ෼ذͰͷϦλʔϯΛආ͚Δ ΞʔϦʔϦλʔϯࣗମ΍ͦͷ৚݅Λݟམͱ͢Մೳੑ͕͋Δ if (type

    == null) { return } val messageText = when (type) { FOO -> "this is FOO" BAR -> "this is BAR" } ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  28. ΞʔϦʔϦλʔϯ: ஫ҙ఺ 2/2 ෆཁͳΞϯϋοϐʔύεΛ࡞Βͳ͍Α͏ʹ͢Δ యܕతͳྫ: ۭͷίϨΫγϣϯʹର͢Δ૸ࠪ if (list.isEmpty) { return

    listOf() } return list .filter { ... } .map { ... } ؔ਺ > ྲྀΕ > ϋοϐʔύεʹয఺Λ౰ͯΔ
  29. ؔ਺Λ෼ׂ͢Δ࣠ 2/2 ໰୊: ͲͪΒͷ࣠Ͱؔ਺Λ෼ׂ͢Δ΂͖ʁ Condition Object Premium account Free account

    Background color Account icon Red Gray “Twemoji” ©Twitter, Inc and other contributors (Licensed under CC-BY 4.0) https://twemoji.twitter.com/ ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ
  30. ৚݅Ͱ෼ׂͨ͠৔߹ʢΑ͘ͳ͍ྫʣ fun bindViewData(accountType: AccountType) { when (accountType) { PREMIUM ->

    updateViewsForPremium() FREE -> updateViewsForFree() } } private fun updateViewsForPremium() { backgroundView.color = PREMIUM_BACKGROUND_COLOR accountTypeIcon.image = resources.getImage(PREMIUM_IMAGE_ID) } ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ
  31. ৚݅ʹΑΔ෼ׂ͕ͳͥʮΑ͘ͳ͍ʯ͔ 2/2 ৚݅ͱର৅ͷ૊Έ߹Θͤͷ໢ཏੑΛอূͰ͖ͳ͍ when (accountType) { PREMIUM -> updateViewsForPremium() FREE

    -> updateViewsForFree() BUSINESS -> updateViewsForBusiness() } private fun updateViewsForBusiness() { backgroundView.color = PREMIUM_BACKGROUND_COLOR // [BUG] Forgot to update the account icon ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ
  32. ର৅ʹΑΔ෼ׂ: Α͍ྫ 1/2 fun bindViewData(accountType: AccountType) { updateBackgroundViewColor(accountType) updateAccountTypeImage(accountType) }

    private fun updateBackgroundViewColor(accountType: AccountType) { backgroundView.color = when (accountType) { PREMIUM -> PREMIUM_BACKGROUND_COLOR FREE -> FREE_BACKGROUND_COLOR } } ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ
  33. ର৅ʹΑΔ෼ׂ: Α͍ྫ 2/2 ۩ମతͳཁ໿͕ॻ͖΍͍͢ /** * Updates background color and

    icon according to a given account type. */ ৚݅ͱର৅ͷ૊Έ߹Θͤͷ໢ཏੑΛอূͰ͖Δ ߋͳΔϦϑΝΫλϦϯάΛద༻Ͱ͖Δ ྫ: நग़ͨؔ͠਺Λࢀরಁաʹ͢Δ ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ
  34. ର৅ʹΑΔ෼ׂ: ߋͳΔϦϑΝΫλϦϯά fun bindViewData(accountType: AccountType) { backgroundView.color = getBackgroundColorInt(accountType) accountTypeIcon.image

    = getAccountTypeIconImage(accountType) } private fun getBackgroundColorInt(accountType: AccountType): Int = when (accountType) { PREMIUM -> PREMIUM_BACKGROUND_COLOR FREE -> FREE_BACKGROUND_COLOR } ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ
  35. ΞʔϦʔϦλʔϯ VS ର৅ʹΑΔ෼ׂ ʮΞʔϦʔϦλʔϯʯ͸ʮ৚݅ʹΑΔ෼ׂʯͰ͸ʁ ઓུ 1: - ΞϯϋοϐʔύεΛϋοϐʔύεʹؚΊΔ ઓུ 2:

    - ઌʹΞʔϦʔϦλʔϯΛద༻͢Δ - ࢒ͬͨϋοϐʔύεʹରͯ͠ର৅ʹΑΔ෼ׂΛద༻͢Δ ؔ਺ > ྲྀΕ > ର৅ʹΑΔ෼ׂ