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. Related book ಡΈ΍͍͢ίʔυͷΨΠυϥΠϯ - ࣋ଓՄೳͳιϑτ΢ΣΞ։ൃͷͨΊʹ - Published on Oct. 22,

    2023. ٕज़ධ࿦ࣾ - Written in Japanese https://gihyo.jp/book/ 2022/978-4-297-13036-7
  2. 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
  3. Why we need readable code To keep high productivity even

    for a large scale product Introduction and Principles > Introduction
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. Topics - Introduction - The boy scout rule - YAGNI

    - KISS - Single responsibility principle - Premature optimization is the root of all evil Introduction and Principles > Principles
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. Topics - Introduction - The boy scout rule - YAGNI

    - KISS - Single responsibility principle - Premature optimization is the root of all evil Introduction and Principles > Principles > YAGNI
  22. 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
  23. 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
  24. 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
  25. 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
  26. Topics - Introduction - The boy scout rule - YAGNI

    - KISS - Single responsibility principle - Premature optimization is the root of all evil Introduction and Principles > Principles > KISS
  27. 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
  28. 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
  29. KISS: Bad example return userActionLog .groupBy ... .map ... .sortedBy

    ... .map ... .takeLast(10) Need to read all to understand: receiver, it Introduction and Principles > Principles > KISS
  30. KISS: Good example val logCountByUser: Map<User, Int> = userActionLog .groupBy

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

    ... val userListSortedByLogCount: List<User> = logCountByUser ... ... return userListSortedByLogCount.takeLast(10) Does not look beautiful, but easier to understand Introduction and Principles > Principles > KISS
  32. 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
  33. 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
  34. 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
  35. 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
  36. Single responsibility principle: Bad example 2/2 class LibraryBookRentalData( val bookIds:

    MutableList<Int>, val bookNames: MutableList<String>, val bookIdToRenterNameMap: MutableMap<Int, String>, val bookIdToDueDateMap: MutableMap<Int, Date>, ... ) { fun findRenterName(bookName: String): String? fun findDueDate(bookName: String): Date? ... Introduction and Principles > Principles > Single responsibility principle
  37. 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
  38. 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<BookData, Entry> ) { data class Entry(val renter: UserData, val dueDate: Date) Introduction and Principles > Principles > Single responsibility principle
  39. 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
  40. 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
  41. 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
  42. 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
  43. Premature optimization 2/2 Good optimization: makes the code simpler Bad

    optimization: makes the code complex Introduction and Principles > Principles > Premature optimization
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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