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

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

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

Munetoshi Ishikawa

May 11, 2023
Tweet

More Decks by Munetoshi Ishikawa

Other Decks in Programming

Transcript

  1. /** Code readability session 3 */
    // Comments

    View Slide

  2. Brushup: Naming
    Use accurate and descriptive names
    - What to describe: "what" rather than "who/when"
    - Grammar: word order
    - Word selection: narrow meaning, non-abbreviated, affirmative

    View Slide

  3. 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
    Comments > Introduction

    View Slide

  4. Comment
    Explanations or notes written in the code
    - Usually ignored by a complier/interpreter
    /**
    * Explanation of `fooFunction`...
    */
    fun fooFunction(parameter: Parameter /* note of the parameter */) {
    barFunction() // Explanation of why `barFunction` is called
    /* A comment with
    multiple lines. */
    Comments > Introduction

    View Slide

  5. Benefits of comments
    - Makes code easy to understand
    - Prevents mistakes
    - Helps refactoring
    We do not need a comment if the code is simple enough
    (depending on the convention)
    Comments > Introduction

    View Slide

  6. Benefits of comments
    - Makes code easy to understand
    - Prevents mistakes
    - Helps refactoring
    We do not need a comment if the code is simple enough
    (depending on the convention)
    Comments > Introduction

    View Slide

  7. Refactoring with comments: Example
    /**
    * Adds a new pair of keyword and the definition to this dictionary,
    * can be referenced by [getDefinition(String)].
    *
    * If the keyword is already registered, this registration fails.
    * Then, this returns a boolean representing whether the registration
    * succeeded.
    */
    fun add(newData: Pair): Boolean
    A long comment compared to the simplicity of the behavior
    Comments > Introduction

    View Slide

  8. Refactoring with comments: Refactoring plan
    Determine why a long comment is needed
    Ideas for improvement
    - Rename the function
    - Split the parameter
    - Simplify the error cases
    - Remove the unnecessary return value
    Comments > Introduction

    View Slide

  9. Refactoring with comments: Refactoring result
    /**
    * Adds or overwrites a definition of a given [keyword].
    * The registered definition is obtained by [getDefinition(String)].
    */
    fun registerDefinition(keyword: String, definitionText: String)
    For simple behavior, write a simple comment
    Comments > Introduction

    View Slide

  10. Types of comments
    - Documentation: Formal comment for class/variable/function...
    /**
    * A list of pairs of a string keyword and the explanation text.
    *
    * ... (details of usage, limitations, etc.)...
    */
    class Dictionary {
    ...
    }
    Comments > Introduction

    View Slide

  11. Types of comments
    - Documentation: Formal comment for class/variable/function...
    - Informal comment: Comment written at various places in code
    // Call `toList` here to create a copied list explicitly.
    val listSnapshot = list.toList()
    Comments > Introduction

    View Slide

  12. Types of comments
    - Documentation: Formal comment for class/variable/function...
    - Informal comment: Comment written at various places in code
    - To do comments:
    // TODO:
    ,
    // FIXME:
    Comments > Introduction

    View Slide

  13. Types of comments
    - Documentation: Formal comment for class/variable/function...
    - Informal comment: Comment written at various places in code
    - To do comments:
    // TODO:
    ,
    // FIXME:
    - Comments for IDE/compiler/code-generation:
    // $COVERAGE-IGNORE$
    Comments > Introduction

    View Slide

  14. Types of comments
    - Documentation: Formal comment for class/variable/function...
    - Informal comment: Comment written at various places in code
    - To do comments:
    // TODO:
    ,
    // FIXME:
    - Comments for IDE/compiler/code-generation:
    // $COVERAGE-IGNORE$
    Comments > Introduction

    View Slide

  15. Roles of documentation and informal comment
    Documentation
    - Allows to understand code without reading it
    - Explains what it is/does
    Informal comment
    - Helps understand code while reading it
    - Explains the overview, reason, background and pitfalls
    Comments > Introduction

    View Slide

  16. Topics
    - Documentation
    - Informal comment
    Comments > Documentation

    View Slide

  17. Topics
    - Documentation
    - Informal comment
    Comments > Documentation

    View Slide

  18. What we write documentation for
    - Class, interface, enum, struct, protocol, trait...
    - Variable, property, field, parameter, constant value...
    - Function, method, procedure, subroutine...
    - Scope, package, module, namespace...
    Comments > Documentation

    View Slide

  19. Format of documentation
    Starts with...
    - `/**` for Kotlin, Java, Swift and Objective-C
    - `///` for Swift and Objective-C
    - `/*!` for Objective-C
    Follow the format of documentation generator
    e.g., KDoc, Javadoc, Swift Markup, HeaderDoc, Doxygen
    Comments > Documentation

    View Slide

  20. Contents of documentation
    Let us take a look at anti-patterns first
    Comments > Documentation

    View Slide

  21. Anti-patterns: Neglecting auto-generated comment
    /**
    * @param keyword
    * @return
    */
    fun getDescription(keyword: String): String
    Comments > Documentation > Anti-patterns

    View Slide

  22. Anti-patterns: Same as the name
    /**
    * Gets the description for a keyword.
    */
    fun getDescription(keyword: String): String
    Comments > Documentation > Anti-patterns

    View Slide

  23. Anti-patterns: Translation of the code
    /**
    * Calls [doA] if `conditionA` is satisfied.
    * Otherwise, calls [doB] and if ...
    */
    fun getDescription(keyword: String): String {
    if (conditionA) {
    doA()
    } else {
    doB()
    if (...) {...}
    }
    Comments > Documentation > Anti-patterns

    View Slide

  24. Anti-patterns: Referring to private members
    /**
    * Returns a string stored in a private map [dictionary].
    */
    fun getDescription(keyword: String): String
    Comments > Documentation > Anti-patterns

    View Slide

  25. Anti-patterns: No summary
    /**
    * Throws an exception if the given `keyword` is empty.
    */
    fun getDescription(keyword: String): String
    Comments > Documentation > Anti-patterns

    View Slide

  26. Anti-patterns: Mentioning to callers
    /**
    * ...
    * This is called by class [UserProfilePresenter].
    */
    fun getDescription(keyword: String): String
    Comments > Documentation > Anti-patterns

    View Slide

  27. Lessons from anti-patterns
    Write documentation only when explanation is required
    - Fine to skip if type/value/procedure name is enough
    Summarize "what it is/does"
    - Without mentioning to callers
    - Without using implementation details
    Comments > Documentation > Anti-patterns

    View Slide

  28. Contents of documentation
    Short summary (Mandatory)
    "What it is/does" in a phrase/sentence
    Details (Optional)
    Additional sentences to explain usages, limitations, and so on
    Comments > Documentation > Overview

    View Slide

  29. Contents of documentation
    Short summary (Mandatory)
    "What it is/does" in a phrase/sentence
    Details (Optional)
    Additional sentences to explain usages, limitations, and so on
    Comments > Documentation > Short summary

    View Slide

  30. How to write short summary
    Techniques
    - Find an important part of code
    - Find common factors of code
    Comments > Documentation > Short summary

    View Slide

  31. How to write short summary: Important code 1/2
    Find the most important line, block, element of the code
    if (!user.isValid) return
    val rawProfileImage = getProfileImage(user.id, ...)
    val roundProfileImage = applyRoundFilter(rawProfileImage, ...)
    profileView.setImage(roundProfileImage)
    Comments > Documentation > Short summary

    View Slide

  32. How to write short summary: Important code 2/2
    Complement information based on the most important point
    /**
    * Shows a roundly cut profile image of a given [user].
    * ...
    */
    ...
    profileView.setImage(roundProfileImage)
    The summary will also be a good hint for naming
    Comments > Documentation > Short summary

    View Slide

  33. How to write short summary: Common factor
    Abstract common factors of the code
    /**
    * Updates message layout with a newly received message data.
    */
    fun ...(receivedMessageData: MessageData) {
    messageView.text = receivedMessageData.contentText
    senderNameView.text = receivedMessageData.senderName
    timestampView.text = receivedMessageData.sentTimeText
    }
    Comments > Documentation > Short summary

    View Slide

  34. Convention of short summary
    Refer to standard library documents Examples: Kotlin, Java, Swift, Objective-C
    - Class, variable: Starts with a noun phrase
    e.g., "A generic ordered collection of elements."4
    - Function: Starts with a verb with 3rd-person singular form
    e.g., "Adds a new element at the end of the array."5
    5 https://developer.apple.com/documentation/swift/array/3126937-append
    4 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/#list
    Comments > Documentation > Short summary

    View Slide

  35. Contents of documentation
    Short summary (Mandatory)
    "What it is/does" in a phrase/sentence
    Details (Optional)
    Additional sentences to explain usages, limitations, and so on
    Comments > Documentation > Details

    View Slide

  36. Contents of "details" in documentation
    - Specification and usage
    - Function return value
    - Limitation and error values/conditions
    - Examples
    - ...
    Comments > Documentation > Details

    View Slide

  37. Contents of "details" in documentation
    - Specification and usage
    - Function return value
    - Limitation and error values/conditions
    - Examples
    Comments > Documentation > Details

    View Slide

  38. Specification and usage
    Comment on typical usage and expected behavior
    /**
    * ...
    * To update view components such as message text and sender name,
    * give [MessageData] model object to [bindView].
    */
    class MessageViewPresenter(messageView: View)
    Comments > Documentation > Details

    View Slide

  39. Contents of "details" in documentation
    - Specification and usage
    - Function return value
    - Limitation and error values/conditions
    - Examples
    Comments > Documentation > Details

    View Slide

  40. Function return value 1/2
    Question: What does the following return value mean?
    fun setSelectedState(isSelected: Boolean): Boolean
    Possible answer:
    isToggled // true if the state is changed
    wasSelected // previous state before the function call
    isSuccessfullyUpdated // true if there is no error
    isSelected // pass through the given `isSelected` value
    ...
    Comments > Documentation > Details

    View Slide

  41. Function return value 2/2
    Comment on a return value if the function name is not enough
    - has side effects for function call
    - has contract on the return value
    Comments > Documentation > Details

    View Slide

  42. Function return value 2/2
    Comment on a return value if the function name is not enough
    - has side effects for function call
    - has contract on the return value
    /**
    * ...
    * ... returns true if it was selected before this function call.
    */
    fun setSelectedState(isSelected: Boolean): Boolean
    Comments > Documentation > Details

    View Slide

  43. Function return value 2/2
    Comment on a return value if the function name is not enough
    - has side effects for function call
    - has contract on the return value
    /**
    * ...
    * The profile ID is non-negative value.
    */
    fun getProfileId(): Int
    Comments > Documentation > Details

    View Slide

  44. Contents of "details" in documentation
    - Specification and usage
    - Function return value
    - Limitation and error values/conditions
    - Examples
    Comments > Documentation > Details

    View Slide

  45. Limitation and error values/status
    Comment on the precondition and what happens on violation
    - A required receiver state to call a function
    - Restrictions on the arguments
    Comments > Documentation > Details

    View Slide

  46. Limitation and error values/status
    Comment on the precondition and what happens on violation
    - A required receiver state to call a function
    - Restrictions on the arguments
    /**
    * ...
    * [prepare] must be called before calling [play] or [seek],
    * or this throws [ResourceNotReadyException].
    */
    class VideoPlayer(videoPath: String)
    Comments > Documentation > Details

    View Slide

  47. Limitation and error values/status
    Comment on the precondition and what happens on violation
    - A required receiver state to call a function
    - Restrictions on the arguments
    /**
    * ...
    * Returns `null` if the given `position` is out of the array range.
    */
    fun valueAt(position: Int): T?
    Comments > Documentation > Details

    View Slide

  48. Limitations: Example
    - Arguments and receiver state
    - Instance lifecycle
    - Caller thread
    - Reentrancy
    - Calculation cost, memory size
    - External environment (e.g., network, database)
    Comments > Documentation > Details

    View Slide

  49. Contents of "details" in documentation
    - Specification and usage
    - Function return value
    - Limitation and error values/conditions
    - Examples
    Comments > Documentation > Details

    View Slide

  50. Examples
    Make code more understandable with examples
    - Example code for usage
    - Parameter or return value example
    /**
    * ... For example, this returns `listOf("a", "bc", "", "d")`
    * for argument `"a, bc ,,d"`
    */
    fun splitByComma(string: String): List {...
    Comments > Documentation > Details

    View Slide

  51. Documentation: Summary
    Target: class, variable, function, scope
    Contents: short summary (mandatory), details (optional)
    Cautions:
    - Write only when the name is insufficient as explanation
    - Do not mention to the caller or the implementation detail
    Comments > Documentation > Summary

    View Slide

  52. Topics
    - Documentation
    - Informal comment
    Comments > Informal comment

    View Slide

  53. What informal comment is: Kotlin case
    // Function explanation, which won't appear on KDoc
    fun function(param /* Parameter explanation */: Param) {
    // Code block summary
    someMethod(value) // Reason of a statement
    newId = param.id + 123 /* Reason of constant value */ + ...
    ...
    - Comment with whatever helps readers
    - Short summary is not mandatory
    Comments > Informal comment

    View Slide

  54. What requires informal comments
    - Large code
    - Complex/unintuitive code
    - Workaround
    Comments > Informal comment

    View Slide

  55. What requires informal comments
    - Large code
    - Complex/unintuitive code
    - Workaround
    Comments > Informal comment

    View Slide

  56. Informal comment for large code
    Make code blocks with comments to summarize what they do
    ...
    val messageKey = ...
    val messageData = messageCache[messageKey]
    ...
    if (messageData == null || ...) { // <- When this satisfies?
    ... // <- Hard to overview code in a nest
    }
    Comments > Informal comment

    View Slide

  57. Informal comment for large code
    Make code blocks with comments to summarize what they do
    // Get message data cache if it's available
    val messageKey = ...
    val messageData = messageCache[messageKey]
    ...
    // Load message data from DB if there's no cached data.
    if (messageData == null || ...) {
    ...
    }
    Comments > Informal comment

    View Slide

  58. What requires informal comments
    - Large code
    - Complex/unintuitive code
    - Workaround
    Comments > Informal comment

    View Slide

  59. Informal comment for unintuitive code
    Explain summary/reason if it is hard to understand
    //
    //
    wordReplacementData.reverse()
    .forEach { (startIndex, endIndex, newText) ->
    stringBuilder.replace(startIndex, endIndex, newText)
    }
    Question: Why do we need to call reverse()?
    Comments > Informal comment

    View Slide

  60. Informal comment for unintuitive code
    Explain summary/reason if it is hard to understand
    // Replace texts in the reverse order because `replace()`
    // affects the following indices.
    wordReplacementData.reverse()
    .forEach { (startIndex, endIndex, newText) ->
    stringBuilder.replace(startIndex, endIndex, newText)
    }
    Prevent from removing reverse() by incorrect "refactoring"
    Comments > Informal comment

    View Slide

  61. What requires informal comments
    - Large code
    - Complex/unintuitive code
    - Workaround
    Comments > Informal comment

    View Slide

  62. Informal comment for workaround
    Explain what a workaround does and explain the reason
    // We restore the previous state here
    // because libraryFunction() may break the receiver state
    Add links to explain
    // To avoid Device-X specific tinting bug (see, ISSUE-123456)
    Comments > Informal comment

    View Slide

  63. Informal comments: Summary
    Essentially the same as documentation
    - Short summary is not mandatory
    Explain large, complex, unintuitive code
    - Code block, summary, reason, links
    Comments > Informal comment

    View Slide

  64. Summary
    - Comment with whatever readers require
    - Refactor before/after writing comments
    - Documentation:
    Short summary (mandatory) and details (optional)
    - Informal comment:
    Explanations for large, complex, unintuitive code
    Comments > Summary

    View Slide