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

Code readability: Session 1 (ver. 2, En)

Code readability: Session 1 (ver. 2, En)

Munetoshi Ishikawa

May 11, 2023
Tweet

More Decks by Munetoshi Ishikawa

Other Decks in Programming

Transcript

  1. Code readability
    Munetoshi Ishikawa

    View Slide

  2. Related book
    ಡΈ΍͍͢ίʔυͷΨΠυϥΠϯ
    - ࣋ଓՄೳͳιϑτ΢ΣΞ։ൃͷͨΊʹ
    - Published on Oct. 22, 2023. ٕज़ධ࿦ࣾ
    - Written in Japanese
    https://gihyo.jp/book/
    2022/978-4-297-13036-7

    View Slide

  3. Code readability session 1
    Introduction and Principles

    View Slide

  4. What readable code is
    - Obvious: isVisible rather than flag
    - Simple: isA && isB rather than !(!isA || !isB) && isB
    - Isolated: functions, classes, modules, etc.
    - Structured: format, dependency, state transition, etc.
    Multiple characteristics must be considered
    Readable code depends on time and context
    Introduction and Principles > Introduction

    View Slide

  5. Why we need readable code
    To keep high productivity even for a large scale product
    Introduction and Principles > Introduction

    View Slide

  6. Product scale and productivity
    Large scale development → Hard to keep high productivity
    value, outcome
    development scale (code, headcount, time)
    Readability: One of the methods to realize high productivity
    Introduction and Principles > Introduction

    View Slide

  7. Product scale and readability
    Reading code > Writing code at a large scale product
    - Understanding existing code to implement a new feature
    - Requesting code review from two or more engineers
    - Complicated bug fix with only one line
    Easy to read is more important than easy to write
    Introduction and Principles > Introduction

    View Slide

  8. Productivity optimization
    Focus on team productivity during the entire product lifecycle
    Your 5 minutes could save 1 hour for others
    Add a comment, write test, refactor
    We may need to update personnel rating criteria
    Don't focus only on short-term speed to implement
    Introduction and Principles > Introduction

    View Slide

  9. Prisoner's dilemma
    Team productivity may decrease if we focus on the personal productivity
    Bob
    Alice Hacky
    Readable
    Readable
    Hacky
    8
    8
    10
    1
    1
    10
    2
    2
    Introduction and Principles > Introduction

    View Slide

  10. How to work on improving readability
    - Choose techniques and knowledge: Remember the objective
    - Balance value and complexity
    - Take advantages of automatic validation: Compiler, test, etc.
    - Discuss frequently: Reduce rework of mistakes
    - Keep learning
    Introduction and Principles > Introduction

    View Slide

  11. Learn how to write readable code
    Feature implementation is relatively easy
    Special training is not required
    No learning, No readable code
    - lectures, training, books, online articles
    - peer code review, pair programming
    Introduction and Principles > Introduction

    View Slide

  12. Contents of this lecture
    - Introduction and Principles
    - Natural language: Naming, Comments
    - Inner type structure: State, Function
    - Inter type structure: Dependency I, Dependency II
    - Follow-up: Review
    Introduction and Principles > Introduction

    View Slide

  13. Contents of this lecture
    - Introduction and Principles
    - Natural language: Naming, Comments
    - Inner type structure: State, Function
    - Inter type structure: Dependency I, Dependency II
    - Follow-up: Review
    Introduction and Principles > Introduction

    View Slide

  14. Topics
    - Introduction
    - The boy scout rule
    - YAGNI
    - KISS
    - Single responsibility principle
    - Premature optimization is the root of all evil
    Introduction and Principles > Principles

    View Slide

  15. Topics
    - Introduction
    - The boy scout rule
    - YAGNI
    - KISS
    - Single responsibility principle
    - Premature optimization is the root of all evil
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  16. The boy scout rule
    Try to leave this world a little better than you found it...
    — Robert Baden-Powell
    Introduced to software development by Robert C. Martin1
    Improve code whenever you touch it
    1 97 Things Every Programmer Should Know: Collective Wisdom from the Experts, Kevlin Henney, 2010
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  17. Dos for the boy scout rule
    - Add: comments, tests
    - Remove: unnecessary dependencies, members, conditions
    - Rename: classes, functions, variables
    - Break: huge classes, huge functions, nests, call sequences
    - Structure: format, dependencies, abstraction layers, hierarchies
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  18. Don'ts for the boy scout rule
    Don't add an element in a huge structure
    Examples
    - Don't add a new member/sentence into a huge class/function
    - Don't add a new layer into a deep call/type hierarchy
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  19. Example of dos and don'ts 1/3
    Question: Is it fine to add a new enum type Z?
    val viewType: ViewType = ... // An enum type
    when (viewType) {
    A -> {
    view1.isVisible = true
    view2.text = "Case A"
    }
    B -> {
    view1.isVisible = false
    view2.text = "Case B"
    }
    ...
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  20. Example of dos and don'ts 2/3
    Answer: Should not add as is
    There are already too many conditional branches
    Solution: Extract values as enum properties
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  21. Example of dos and don'ts 3/3
    1: Extract values as properties
    enum class ViewType(val isView1Visible: Boolean, val view2Text: String)
    2: Remove conditional branches with the properties
    view1.isVisible = viewType.isView1Visible
    view2.text = viewType.view2Text
    3: Add a new type Z
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  22. The boy scout rule: Note
    Don't make too large of a pull-request or commit
    - Refactor before implementing
    Consider the affected area
    - Decide the scope of refactoring in advance
    - Don't refactor at the release branch
    Introduction and Principles > Principles > The boy scout rule

    View Slide

  23. Topics
    - Introduction
    - The boy scout rule
    - YAGNI
    - KISS
    - Single responsibility principle
    - Premature optimization is the root of all evil
    Introduction and Principles > Principles > YAGNI

    View Slide

  24. YAGNI
    You Aren't Gonna Need It
    Implement only when required
    - 90% of features for the future are not used 2
    - Keep structure simple = ready for unexpected change 2
    2 http://www.extremeprogramming.org/rules/early.html
    Introduction and Principles > Principles > YAGNI

    View Slide

  25. YAGNI: Example 1/2
    Unused code
    - Classes/functions/variables not referred
    - Code commented out
    Overextended code
    - Abstract type with only one implementation
    - Function parameter only for a constant value
    Introduction and Principles > Principles > YAGNI

    View Slide

  26. YAGNI: Example 2/2
    Add a unit type into UI coordinate model
    class Coordinate(val x: Int, val y: Int, val unitType: UnitType)
    enum class UnitType { PIXEL, POINT }
    The definition of Coordinate + Coordinate will be complicated
    An unused feature can easily lead to inappropriate design
    Introduction and Principles > Principles > YAGNI

    View Slide

  27. YAGNI: Note
    Focuses on feature implementation
    - Discussion is necessary: design, whether feature is needed
    Assumes that the code is modifiable
    - Needs attention for public API or external library
    - Requires system to update
    Introduction and Principles > Principles > YAGNI

    View Slide

  28. Topics
    - Introduction
    - The boy scout rule
    - YAGNI
    - KISS
    - Single responsibility principle
    - Premature optimization is the root of all evil
    Introduction and Principles > Principles > KISS

    View Slide

  29. KISS
    Keep It Simple Stupid
    — Clarence Leonard "Kelly" Johnson
    Choose a simpler solution
    - Use the standard implementation as far as possible
    - Limit and specify the usage of a library/framework/design
    Beautiful code is not always readable
    Introduction and Principles > Principles > KISS

    View Slide

  30. KISS: Bad example
    return userActionLog
    .groupBy { it.user }
    .map { it.key to it.value.size }
    .sortedBy { it.second }
    .map { it.first }
    .takeLast(10)
    Need to read all to understand: receiver, it
    Introduction and Principles > Principles > KISS

    View Slide

  31. KISS: Bad example
    return userActionLog
    .groupBy ...
    .map ...
    .sortedBy ...
    .map ...
    .takeLast(10)
    Need to read all to understand: receiver, it
    Introduction and Principles > Principles > KISS

    View Slide

  32. KISS: Good example
    val logCountByUser: Map = userActionLog
    .groupBy { log -> log.user }
    .map { (user, logs) -> user to logs.size }
    val userListSortedByLogCount: List = logCountByUser
    .sortedBy { (_, messageCount) -> messageCount }
    .map { (userId, _) -> userId }
    return userListSortedByLogCount.takeLast(10)
    Does not look beautiful, but easier to understand
    Introduction and Principles > Principles > KISS

    View Slide

  33. KISS: Good example
    val logCountByUser: Map = userActionLog
    ...
    ...
    val userListSortedByLogCount: List = logCountByUser
    ...
    ...
    return userListSortedByLogCount.takeLast(10)
    Does not look beautiful, but easier to understand
    Introduction and Principles > Principles > KISS

    View Slide

  34. Topics
    - Introduction
    - The boy scout rule
    - YAGNI
    - KISS
    - Single responsibility principle
    - Premature optimization is the root of all evil
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  35. Single method == small responsibilityʁ
    No. Number of methods != Amount of responsibility
    class Alviss {
    // May show a text, may break the device, may launch a rocket,
    // may ...
    fun doEverything(state: UniverseState)
    }
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  36. Single responsibility principle
    A class should have only one reason to change.
    — Robert C. Martin
    Should not mix up two unrelated features
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  37. Single responsibility principle: Bad example 1/2
    Book rental state of a library
    Book rental status
    Definition and list of books
    Definition and list of users
    Entries of rental status (user, due date)
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  38. Single responsibility principle: Bad example 2/2
    class LibraryBookRentalData(
    val bookIds: MutableList,
    val bookNames: MutableList,
    val bookIdToRenterNameMap: MutableMap,
    val bookIdToDueDateMap: MutableMap, ...
    ) {
    fun findRenterName(bookName: String): String?
    fun findDueDate(bookName: String): Date?
    ...
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  39. Single responsibility principle: How to improve 1/2
    Split a model class for each entity
    Rental state model
    Definition of book
    Definition of user
    Entry of rental state (user, due date)
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  40. Single responsibility principle: How to improve 2/2
    data class BookData(val id: Int, val name: String, ...)
    data class UserData(val name: String, ...)
    class CirculationRecord(
    val onLoanBookEntries: MutableMap
    ) {
    data class Entry(val renter: UserData, val dueDate: Date)
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  41. Keep responsibility small
    Split classes
    - Model for each entity
    - Logic for each layer and component
    - Utility for each target type
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  42. How to confirm responsibility
    List what the class does and try to summarize it
    Split the class for each case as follows:
    - It's hard to make a summary
    - The summary is too long compared with the name
    Introduction and Principles > Principles > Single responsibility principle

    View Slide

  43. Topics
    - Introduction
    - The boy scout rule
    - YAGNI
    - KISS
    - Single responsibility principle
    - Premature optimization is the root of all evil
    Introduction and Principles > Principles > Premature optimization

    View Slide

  44. Premature optimization 1/2
    We should forget about small efficiencies,
    say about 97% of the time:
    premature optimization is the root of all evil.
    — Structured Programming with go to Statements, Donald Knuth
    Introduction and Principles > Principles > Premature optimization

    View Slide

  45. Premature optimization 2/2
    Good optimization: makes the code simpler
    Bad optimization: makes the code complex
    Introduction and Principles > Principles > Premature optimization

    View Slide

  46. Example of good optimization
    Before optimization:
    val data = arrayList.find { data -> data.key == expectedKey }
    After optimization:
    val data = hashMap[expectedKey]
    Simplify the code while reducing the calculation cost
    Introduction and Principles > Principles > Premature optimization

    View Slide

  47. Optimization making code complex 1/2
    Yet we should not pass up our opportunities in that critical 3%
    — Donald Knuth
    Introduction and Principles > Principles > Premature optimization

    View Slide

  48. Optimization making code complex 2/2
    - Mutable instance reusing
    - Cache
    - Instance pool
    - Lazy initialization
    Requires platform support or profiling
    Introduction and Principles > Principles > Premature optimization

    View Slide

  49. Drawbacks of optimization
    May obstruct simplification
    - Optimizer may be smarter
    May require overhead cost
    - Cache: cache miss ratio access time
    - Lazy initialization: (synchronized) instance check
    Introduction and Principles > Principles > Premature optimization

    View Slide

  50. Required actions before optimization
    Check if the optimization is reasonable
    Balance value and complexity
    Profile/estimate
    Target (time, memory), amount, rate
    Introduction and Principles > Principles > Premature optimization

    View Slide

  51. Summary
    Readability is for sustainable development
    The boy scout rule: Make code readable before changing it
    YAGNI: Implement only when required
    KISS: Choose a simple solution, beautiful != readable
    Single responsibility principle: Clarify the scope
    Premature optimization: Profile/estimate before optimization
    Introduction and Principles > Summary

    View Slide