# TotT

Published articles for TotT.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Prefactoring: Clear the Way for Your New Feature

DevFeed: [Prefactoring: Clear the Way for Your New Feature](<https://devfeed.tech/articles/prefactoring-clear-the-way-for-your-new-feature-23872.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/07/prefactoring-clear-way-for-your-new.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-07-21T18:52:05Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Refactoring](<https://devfeed.tech/topics/refactoring.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [code](<https://devfeed.tech/tags/code.md>), [rahul-singal](<https://devfeed.tech/tags/rahul-singal.md>), [refactoring](<https://devfeed.tech/tags/refactoring.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

The article explains prefactoring, or preparatory refactoring: restructuring existing code before implementing a planned feature. It presents this as a way to make feature work fit the code naturally, speed up reviews, reduce bugs, and enable safer rollbacks.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Rahul Singal "First make the change easy, then make the easy change." - paraphrased from Kent Beck You're working on a new feature, but the existing code wasn't written with future changes in mind. Trying to force the feature in directly gets complicated fast. One change leads to another, and before you know it you're already a few files deep fixing things you never planned to touch. Prefactoring (short for "preparatory refactoring") is the practice of reworking existing code to make it more suitable for an upcoming change before you actually implement the new functionality. Instead of cleaning up code as an afterthought or trying to force a new feature into an incompatible structure, you restructure the codebase first. Prefactoring helps you: Easily implement new features: Restructuring the codebase first ensures your new feature fits naturally into the code. Speed up reviews: It's easier to review the refactoring and the feature in separate changes. Avoid bugs: Isolating cleanups from functional logic can help prevent bugs. Roll back safely: If you need to roll back, it is much easier to revert small, focused changes. Here is a simplified example of a prefactoring change: Change 1 (Prefactoring) Extract display name helper to remove duplication. Change 2 (Feature) Add middle name support. + def get_display_name(user): + return f"{user.first_name} {user.last_name}" # Profile page - display_name = f"{user.first_name} {user.last_name}" + display_name = get_display_name(user) # Email template - greeting = f"Hi {user.first_name} {user.last_name}," + greeting = f"Hi {get_display_name(user)}," def get_display_name(user): - return f"{user.first_name} {user.last_name}" + return f"{user.first_name} {user.middle_name} {user.last_name}" You can prefactor a change that is already in review too! If your reviewe

## Choosing Values for Robust Tests

DevFeed: [Choosing Values for Robust Tests](<https://devfeed.tech/articles/choosing-values-for-robust-tests-23871.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/06/choosing-values-for-robust-tests.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-06-04T12:47:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [test](<https://devfeed.tech/topics/test.md>), [Code](<https://devfeed.tech/topics/code.md>), [implementation](<https://devfeed.tech/topics/implementation.md>), [bug](<https://devfeed.tech/topics/bug.md>), [Fuzzing/Fuzz testing](<https://devfeed.tech/topics/fuzzing.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [bug](<https://devfeed.tech/tags/bug.md>), [code](<https://devfeed.tech/tags/code.md>), [fuzzing](<https://devfeed.tech/tags/fuzzing.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [radion-khait](<https://devfeed.tech/tags/radion-khait.md>), [test](<https://devfeed.tech/tags/test.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>), [tott](<https://devfeed.tech/tags/tott.md>), [unit-test](<https://devfeed.tech/tags/unit-test.md>)

### AI overview

The article explains how default-valued test inputs can let broken implementations pass unnoticed. It recommends non-default values, varied scenarios, boundary and special-case inputs, fuzzing, and distinct values for each parameter to improve test coverage and confidence.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Radion Khait A test passes. Great! But does it really mean your code is working as expected? Not necessarily.Sometimes the values you choose in your tests can create a false sense of security, especially when dealing with default values. Consider this snippet of a simple map class and its corresponding unit test: Implementation Test void MyMap::insert(int key, int value) { // Oops! The map entry is default-initialized, // the second parameter is not used. internal_map_[key]; } TEST(MyMapTest, Insert) { MyMap my_map; my_map.insert(1, 0); // This passes! EXPECT_EQ(my_map.get(1), 0); } The test passes, but the insert method is broken! It never actually stores the value. The test only passes because the default value for an integer in the map (0) happens to match the value used in the test. When choosing test values, consider the following: Test with non-default values. Explicitly test with values different from the type's default (e.g., non-zero numbers, non-empty strings, enum values other than the one at index 0). This provides greater confidence that your code is actually using the provided input. TEST(MyMapTest, Insert) { MyMap my_map; my_map.insert(1, 5); // This test would fail and reveal the bug in // the implementation above: "Expected 5, got 0". EXPECT_EQ(my_map.get(1), 5); } Test multiple inputs that cover different scenarios, where it is reasonable to do so. Consider empty/missing/null values, numerical boundaries, and special cases that trigger complex logic. Try to cover all distinct code/logic paths. Consider using fuzzing to more thoroughly cover the input domain. Use different values for each input. This guarantees the code under test doesn't accidentally reuse a single input or switch their order. Parameterized testing can also help test a large variety of inputs with minimal code dupl

## Code Review Responses: Add Context When It Counts

DevFeed: [Code Review Responses: Add Context When It Counts](<https://devfeed.tech/articles/code-review-responses-add-context-when-it-counts-23869.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/05/code-review-responses-add-context-when.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-05-12T12:30:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code review](<https://devfeed.tech/topics/code-review.md>), [context](<https://devfeed.tech/topics/context.md>), [engineering-culture](<https://devfeed.tech/topics/engineering-culture.md>)

Tags: [code-comments](<https://devfeed.tech/tags/code-comments.md>), [code-review](<https://devfeed.tech/tags/code-review.md>), [context](<https://devfeed.tech/tags/context.md>), [saicharan-nimmala](<https://devfeed.tech/tags/saicharan-nimmala.md>), [test](<https://devfeed.tech/tags/test.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This Google Tech on the Toilet article explains that code review responses should include brief context when a code change or discussion does not make the resolution obvious. It gives examples involving edge-case tests, design trade-offs, and offline discussions.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Saicharan Nimmala When responding to code review comments, responses like "Done," "Updated," or "Fixed" are commonly used to indicate addressing a suggestion. However, sometimes, a little extra context adds a lot of clarity. Next time you resolve a code review comment, ask yourself: "Is how I addressed the comment completely obvious from the code change and comment thread?" If not, supplement your response with a brief note to clarify the "why" or "how." Your reviewers will thank you. When is it helpful to add context to a code review comment response? Here are a few examples: Your code change doesn't fully explain how you addressed the comment. Providing a brief summary helps the reviewer verify the changes without re-examining every line of the delta, and creates a clearer historical record. Reviewer: This approach seems risky. It might not handle all the edge cases properly. Less helpful response: More helpful response: Author: Updated. Good catch. I've added checks for null, empty, and negative inputs, each with a new test case. Thanks! You made a design choice or trade-off that isn't self-evident. Capturing the reasoning behind a choice provides valuable context. Note that non-obvious design choices within the code should ideally be explained in code comments or the commit description as well. Reviewer: Consider using a more performant library for this data transformation. Less helpful response: More helpful response: Author: I'll go with Y. Done. I considered Library X, but stuck with Library Y because our datasets here are typically small, so the performance difference is negligible, and Library Y has a much simpler API. An offline discussion influenced the solution. Briefly summarizing the outcome or key reasoning from an offline sync ensures that other reviewers, who only see the final code

## Construct with Collaborators, Call with Work

DevFeed: [Construct with Collaborators, Call with Work](<https://devfeed.tech/articles/construct-with-collaborators-call-with-work-23870.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/05/construct-with-collaborators-call-with.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-05-05T12:28:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [business logic](<https://devfeed.tech/topics/business-logic.md>)

Tags: [business-logic](<https://devfeed.tech/tags/business-logic.md>), [code](<https://devfeed.tech/tags/code.md>), [shahar-roth](<https://devfeed.tech/tags/shahar-roth.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

A coding guideline explains that long-lived dependencies should be supplied through a constructor, while inputs that vary for each operation should be passed to methods. A ReportGenerator example separates its database and formatter collaborators from a per-call date range.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Shahar Roth Classes require various objects and parameters to function. The "Construct with Collaborators, Call with Work" guideline can help you construct effective inputs: Use the constructor for collaborators--the dependencies that establish the object's identity. Collaborators stay with the object for its lifetime to enable it to fulfill its ongoing duties. Pass work--the parameters that change with each interaction--to methods. Unique to each call, these inputs provide the specific data needed for an operation such as a file path or database query. Consider a ReportGenerator that needs a database, a formatter, and a date range to generate a report. The database and formatter, as collaborators, are injected via the constructor, while dateRange, which varies per report generation, is passed as a method parameter to the generate method: class ReportGenerator { private final Database database; private final Formatter formatter; // database and formatter are passed as collaborators. ReportGenerator(Database database, Formatter formatter) { this.database = database; this.formatter = formatter; } // dateRange is passed as a parameter. Report generate(Range<Instant> dateRange) { return formatter.format(database.getRecords(dateRange)); } } A single ReportGenerator object can generate multiple reports with different date ranges: ReportGenerator generator = new ReportGenerator(database, formatter); Report report1 = generator.generate(dateRange1); Report report2 = generator.generate(dateRange2); Following the "Construct with Collaborators, Call with Work" guideline promotes: Reusability: Enables instances to be used for multiple, distinct operations. Testability: Separates dependency setup from business logic. Cleaner code: Hides implementation dependencies from the object's users. Predictable behavior: Locks

## One Map Key, One Lookup

DevFeed: [One Map Key, One Lookup](<https://devfeed.tech/articles/one-map-key-one-lookup-23868.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/04/one-map-key-one-lookup.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-04-29T12:26:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Optimization](<https://devfeed.tech/topics/optimization.md>), [cpu](<https://devfeed.tech/topics/cpu.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Go Language](<https://devfeed.tech/topics/go-language.md>), [Java](<https://devfeed.tech/topics/java.md>), [container](<https://devfeed.tech/topics/container.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [code](<https://devfeed.tech/tags/code.md>), [container](<https://devfeed.tech/tags/container.md>), [cpu](<https://devfeed.tech/tags/cpu.md>), [go](<https://devfeed.tech/tags/go.md>), [java](<https://devfeed.tech/tags/java.md>), [optimization](<https://devfeed.tech/tags/optimization.md>), [roman-govsheev](<https://devfeed.tech/tags/roman-govsheev.md>), [tech](<https://devfeed.tech/tags/tech.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This Google Tech on the Toilet article explains how checking for a map key and then fetching its value performs redundant work. It recommends retrieving the value once and reusing it, with corresponding idioms in Python, Go, C++, and Java, and discusses avoiding similar check-then-act patterns when counting or initializing values.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Roman Govsheev Can you spot the wasted CPU cycles in the map usage? if employee_id in employees: mail_to(employees[employee_id].email_address) The redundant lookup caused the waste by performing a check (in) and a fetch ([]) as two separate operations when one is sufficient. Every lookup involves a cost--whether it's computing a hash and scanning buckets or performing an O(log n) traversal. These costs add up quickly. But avoiding them isn't just "premature optimization"--it's about writing cleaner, more robust code that stays efficient at scale and prevents potential race conditions. Instead of paying this cost twice, perform the lookup once and reuse the result: if (employee := employees.get(employee_id)) is not None: mail_to(employee.email_address) Assigning the search result to a variable avoids a second lookup. This efficiency is native to Go via the "comma ok" idiom (val, ok := map[key]) and C++ using map.find(key), both handling retrieval and existence in a single pass. The same inefficiency applies when counting or initializing default. Stop checking for presence; instead, use idioms that handle missing keys automatically at the container level: The redundant way The efficient way If key not in counts: counts[key] = 1 else: counts[key] += 1 counts = defaultdict(int) # Initializes 0 automatically # ... other logic ... counts[key] += 1 Here are some details depending on which language you use: C++: operator[] returns a reference to the value--automatically inserting a default (like 0) if the key is missing--allowing the increment to happen in place. Java: Use map.computeIfAbsent() to perform retrieval and updates in a single call. This is more concise and, on concurrent collections, has the potential to be thread-safe--preventing the "check-then-act" race conditions common with separate contains an

## The Way of TDD

DevFeed: [The Way of TDD](<https://devfeed.tech/articles/the-way-of-tdd-23867.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/03/the-way-of-tdd.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-03-10T12:24:00Z

Content type: article

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Test-driven development](<https://devfeed.tech/topics/tdd.md>), [Test coverage](<https://devfeed.tech/topics/coverage.md>), [Development](<https://devfeed.tech/topics/development.md>), [Algorithm](<https://devfeed.tech/topics/algorithm.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [algorithm](<https://devfeed.tech/tags/algorithm.md>), [article](<https://devfeed.tech/tags/article.md>), [bartosz-papis](<https://devfeed.tech/tags/bartosz-papis.md>), [bugs](<https://devfeed.tech/tags/bugs.md>), [code](<https://devfeed.tech/tags/code.md>), [development](<https://devfeed.tech/tags/development.md>), [quality](<https://devfeed.tech/tags/quality.md>), [refactor](<https://devfeed.tech/tags/refactor.md>), [tdd](<https://devfeed.tech/tags/tdd.md>), [test](<https://devfeed.tech/tags/test.md>), [test-coverage](<https://devfeed.tech/tags/test-coverage.md>), [tests](<https://devfeed.tech/tags/tests.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This article explains Test-Driven Development as a red-green-refactor cycle: write a failing test, make it pass with minimal production code, and then refactor. It describes reported benefits and limitations, and demonstrates the process by modifying a voting algorithm to support abstentions.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Bartosz Papis Test-Driven Development (TDD) is the practice of working in a structured cycle where writing tests comes before writing production code. The process involves three steps, sometimes called the red-green-refactor cycle: Write a failing test Make the test pass by writing just enough production code Refactor the production code to meet your quality standards Research shows TDD has several benefits: it improves test coverage, reduces the number of bugs, increases confidence, and facilitates code reuse. This practice also helps reduce distractions and keep you in the flow. TDD also has its limitations and is not a silver bullet! See the Wikipedia article about TDD for a detailed explanation and references. Here is a short practical example. Assume you need to modify the following voting algorithm to support the option for voters to abstain: def outcome(ballots): if ballots.count(Vote.FOR) > len(ballots) / 2: return "Approved" return "Rejected" 1. We start by writing a failing test - as expected, the test doesn't even compile: def test_abstain_doesnt_count(self): self.assertEqual(outcome([Vote.FOR, Vote.FOR, Vote.AGAINST, Vote.ABSTAIN]), "Approved") 2. We fix the compilation error by including the missing enum option: class Vote(Enum): FOR = 1 AGAINST = 2 ABSTAIN = 3 Now that the test compiles, we fix the production code to get all tests passing: def outcome(ballots): if ballots.count(Vote.FOR) > (len(ballots) - ballots.count(Vote.ABSTAIN)) / 2: return "Approved" return "Rejected" 3. We now refactor the code to improve clarity, and complete an iteration of the TDD cycle: def outcome(ballots): counts = collections.Counter(ballots) return "Approved" if counts[Vote.FOR] > counts[Vote.AGAINST] else "Rejected" Learn more about TDD in the book Test Driven Development: By Example, by Kent Beck.

## Set Safe Defaults for Flags

DevFeed: [Set Safe Defaults for Flags](<https://devfeed.tech/articles/set-safe-defaults-for-flags-23866.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2026/03/set-safe-defaults-for-flags.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2026-03-03T14:47:00Z

Content type: article

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Command-line interface](<https://devfeed.tech/topics/cli.md>), [Utility Software](<https://devfeed.tech/topics/utility.md>), [data](<https://devfeed.tech/topics/data.md>), [Shell](<https://devfeed.tech/topics/shell.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [command-line](<https://devfeed.tech/tags/command-line.md>), [commands](<https://devfeed.tech/tags/commands.md>), [documentation](<https://devfeed.tech/tags/documentation.md>), [google](<https://devfeed.tech/tags/google.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [safety](<https://devfeed.tech/tags/safety.md>), [tott](<https://devfeed.tech/tags/tott.md>), [zhe-lu](<https://devfeed.tech/tags/zhe-lu.md>)

### AI overview

This article explains how to choose safe defaults for command-line flags so that mistakes are less likely to cause harmful changes. It recommends strategies such as defaulting to dry runs, requiring confirmation for irreversible actions, and writing documentation commands with safer behavior.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Zhe Lu We all make mistakes. But big mistakes can cause big headaches! Suppose you're writing a utility to update production data for a launch. Before making changes to production data, you want to perform a dry run to validate the expected changes. In your excitement, you forget to include the --dry_run flag in your command: $ /scripts/credit_accounts --amount=USD10 # Oops, I forgot to include --dry_run You realize your mistake too late. Safe flag defaults can prevent a simple mistake from turning into a major outage: Flag has unsafe default: cliArgs.addBoolFlag(name="dry_run", default=False, help="If set, print change summary, but do NOT change data.") Flag has safe default: cliArgs.addBoolFlag(name="dry_run", default=True, help="If set, print change summary, but do NOT change data.") Safety depends on context: When defining flags, choose the default that minimizes the cost of potential mistakes. This might involve defaulting to a "dry" run, asking for user confirmation before irreversible actions, requiring a confirmation flag on the command line, or other strategies. If you're writing documentation that contains commands, always set values to minimize the damage if run blindly: Flag in documentation has unsafe default: ## How to commit changes Use this command to commit changes. Use --dry_run to test and compute and report changes. ```shell /scripts/credit_accounts --amount=[value] --filter=[conditions] ``` Flag in documentation has safe default: ## How to commit changes Use this command to compute and report changes. Use --nodry_run to commit the changes. ```shell /scripts/credit_accounts --amount=[value] --filter=[conditions] ``` Similarly, consider requiring that environment-specific flags (e.g., backend addresses and output folders) be explicitly set. In this situation, unspecified environme

## Simplify Your Code: Functional Core, Imperative Shell

DevFeed: [Simplify Your Code: Functional Core, Imperative Shell](<https://devfeed.tech/articles/simplify-your-code-functional-core-imperative-shell-23865.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2025/10/simplify-your-code-functional-core.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2025-10-20T13:53:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [IO](<https://devfeed.tech/topics/io.md>)

Tags: [arham-jain](<https://devfeed.tech/tags/arham-jain.md>), [business-logic](<https://devfeed.tech/tags/business-logic.md>), [code](<https://devfeed.tech/tags/code.md>), [database](<https://devfeed.tech/tags/database.md>), [email](<https://devfeed.tech/tags/email.md>), [function](<https://devfeed.tech/tags/function.md>), [functional](<https://devfeed.tech/tags/functional.md>), [map](<https://devfeed.tech/tags/map.md>), [mutation](<https://devfeed.tech/tags/mutation.md>), [network](<https://devfeed.tech/tags/network.md>), [state](<https://devfeed.tech/tags/state.md>), [test](<https://devfeed.tech/tags/test.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This tutorial explains the functional core, imperative shell pattern: keep pure, testable business logic separate from side effects such as database calls, network requests, email delivery, and external state mutation. It demonstrates the pattern by refactoring expiration-notification code.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Arham Jain Is your code a tangled mess of business logic and side effects? Mixing database calls, network requests, and other external interactions directly with your core logic can lead to code that's difficult to test, reuse, and understand. Instead, consider writing a functional core that's called from an imperative shell. Separating your code into functional cores and imperative shells makes it more testable, maintainable, and adaptable. The core logic can be tested in isolation, and the imperative shell can be swapped out or modified as needed. Here's some messy example code that mixes logic and side effects to send expiration notification emails to users: // Bad: Logic and side effects are mixed function sendUserExpiryEmail(): void { for (const user of db.getUsers()) { if (user.subscriptionEndDate > Date.now()) continue; if (user.isFreeTrial) continue; email.send(user.email, "Your account has expired " + user.name + "."); } } A functional core should contain pure, testable business logic, which is free of side effects (such as I/O or external state mutation). It operates only on the data it is given. An imperative shell is responsible for side effects, like database calls and sending emails. It uses the functions in your functional core to perform the business logic. Rewriting the above code to follow the functional core / imperative shell pattern might look like: Functional core function getExpiredUsers(users: User[], cutoff: Date): User[] { return users.filter(user => user.subscriptionEndDate <= cutoff && !user.isFreeTrial); } function generateExpiryEmails(users: User[]): Array<[string, string]> { return users.map(user => ([user.email, "Your account has expired " + user.name + "."]) ); } Imperative shell email.bulkSend(generateExpiryEmails(getExpiredUsers(db.getUsers(), Date.now()))); No

## Sort Lines in Source Code

DevFeed: [Sort Lines in Source Code](<https://devfeed.tech/articles/sort-lines-in-source-code-23864.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2025/09/sort-lines-in-source-code.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2025-09-15T13:45:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Sorting](<https://devfeed.tech/topics/sorting.md>), [Code](<https://devfeed.tech/topics/code.md>), [bug](<https://devfeed.tech/topics/bug.md>), [configuration](<https://devfeed.tech/topics/configuration.md>)

Tags: [bug](<https://devfeed.tech/tags/bug.md>), [code](<https://devfeed.tech/tags/code.md>), [config](<https://devfeed.tech/tags/config.md>), [configuration](<https://devfeed.tech/tags/configuration.md>), [env-file-security](<https://devfeed.tech/tags/env-file-security.md>), [git](<https://devfeed.tech/tags/git.md>), [kyle-freeman](<https://devfeed.tech/tags/kyle-freeman.md>), [sorting](<https://devfeed.tech/tags/sorting.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This Google Tech on the Toilet article explains how duplicate configuration flags can cause bugs and shows how the keep-sorted tool can sort source code, configuration, and text files to make such errors easier to spot and maintain.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Kyle Freeman Imagine you're adding a two-player mode to a game. When testing the feature, you launch the game but don't see the option to add a second player. The configuration looks correct; you enabled two-player mode on the last line! So what happened? Can you spot the bug in the following example? allow_warping: false enable_two_players: false show_end_credits: true enable_frost_band: false enable_two_players: true Using keep-sorted (github.com/google/keep-sorted) to sort lines makes the error easy to spot: the flag enable_two_players is set twice, with different values: # keep-sorted start allow_warping: false enable_frost_band: false enable_two_players: false enable_two_players: true show_end_credits: true # keep-sorted end Sorted lists and lines of code are easier to read and maintain, and can help prevent bugs. To use keep-sorted in your source code, config, and text files, install keep-sorted and then follow these instructions: Add keep-sorted start and keep-sorted end comments in your file, surrounding the lines you want to sort. Run keep-sorted: keep-sorted [file1] [file2] ... (Optional) Add keep-sorted to your pre-commit so it runs automatically on git commit You can add options to override default behavior. For example, you can ignore case, sort numerically, order by prefixes, and even sort by regular expressions: bosses := []int{ // keep-sorted start by_regex=//.* 111213, // Aethon Annie 52816, // Blazing Benny 711, // Daisy Dragon 1003, // Kenzie Kraken // keep-sorted end } Remember: before sorting, ensure the original order isn't intentional. For example, order can be critical when loading dependencies.

## Arrange Your Code to Communicate Data Flow

DevFeed: [Arrange Your Code to Communicate Data Flow](<https://devfeed.tech/articles/arrange-your-code-to-communicate-data-flow-23863.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2025/01/arrange-your-code-to-communicate-data.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2025-01-07T13:59:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [cognitive-load](<https://devfeed.tech/tags/cognitive-load.md>), [readability](<https://devfeed.tech/tags/readability.md>), [sebastian-dorner](<https://devfeed.tech/tags/sebastian-dorner.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

The article explains how arranging adjacent lines of code to follow data flow can improve readability and reduce cognitive load. It uses sandwich-making examples to show grouping related operations, adding blank lines between code blocks, and handling values reused for logging.

### Source excerpt

This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Sebastian Dörner We often read code linearly, from one line to the next. To make code easier to understand and to reduce cognitive load for your readers, make sure that adjacent lines of code are coherent. One way to achieve this is to order your lines of code to match the data flow inside your method: fun getSandwich( bread: Bread, pasture: Pasture ): Sandwich { // This alternates between milk- // bread-related code. val cow = pasture.getCow() val slicedBread = bread.slice() val milk = cow.getMilk() val toast = toastBread(slicedBread) val cheese = makeCheese(milk) return Sandwich(cheese, toast) } fun getSandwich( bread: Bread, pasture: Pasture ): Sandwich { // Linear flow from cow to milk // to cheese. val cow = pasture.getCow() val milk = cow.getMilk() val cheese = makeCheese(milk) // Linear flow from bread to slicedBread // to toast. val slicedBread = bread.slice() val toast = toastBread(slicedBread) return Sandwich(cheese, toast) } To visually emphasize the grouping of related lines, you can add a blank line between each code block. Often you can further improve readability by extracting a method, e.g., by extracting the first 3 lines of the function on the above right into a getCheese method. However, in some scenarios, extracting a method isn't possible or helpful, e.g., if data is used a second time for logging. If you order the lines to match the data flow, you can still increase code clarity: fun getSandwich(bread: Bread, pasture: Pasture): Sandwich { // Both milk and cheese are used below, so this can't easily be extracted into // a method. val cow = pasture.getCow() val milk = cow.getMilk() reportFatContentToStreamz(cow.age, milk) val cheese = makeCheese(milk) val slicedBread = bread.slice() val toast = toastBread(slicedBread) logWarningIfAnyExpired(bread, toast, milk, cheese) return Sand

## Google Renames Testing on the Toilet as Tech on the Toilet

DevFeed: [Google Renames Testing on the Toilet as Tech on the Toilet](<https://devfeed.tech/articles/tech-on-the-toilet-driving-software-excellence-one-bathroom-break-at-a-time-23862.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/12/tech-on-toilet-driving-software.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-12-03T13:34:00Z

Content type: article

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Development](<https://devfeed.tech/topics/development.md>), [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>), [Testing](<https://devfeed.tech/topics/testing.md>), [Google](<https://devfeed.tech/topics/google.md>)

Tags: [andrew-trenk](<https://devfeed.tech/tags/andrew-trenk.md>), [development](<https://devfeed.tech/tags/development.md>), [kanu-tewary](<https://devfeed.tech/tags/kanu-tewary.md>), [software](<https://devfeed.tech/tags/software.md>), [software-development](<https://devfeed.tech/tags/software-development.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [software-testing](<https://devfeed.tech/tags/software-testing.md>), [tech](<https://devfeed.tech/tags/tech.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

Google's weekly Tech on the Toilet publication has been renamed from Testing on the Toilet to reflect its broader coverage of software development topics, including coding practices, machine learning, and web development.

### Source excerpt

By Kanu Tewary and Andrew Trenk Tech on the Toilet (TotT) is a weekly one-page publication about software development that is posted in bathrooms in Google offices worldwide. At Google, TotT is a trusted source for high quality technical content and software engineering best practices. TotT episodes relevant outside Google are posted to this blog. We have been posting TotT to this blog since 2007. We're excited to announce that Testing on the Toilet has been renamed Tech on the Toilet. TotT originally covered only software testing topics, but for many years has been covering any topics relevant to software development, such as coding practices, machine learning, web development, and more. A Cultural Institution TotT is a grassroots effort with a mission to deliver easily-digestable one-pagers on software development to engineers in the most unexpected of places: bathroom stalls! But TotT is more than just bathroom reading -- it's a movement. Driven by a team of 20-percent volunteers, TotT empowers Google employees to learn and grow, fostering a culture of excellence within the Google engineering community. Photos of TotT posted in bathroom stalls at Google. Anyone at Google can author a TotT episode (regardless of tenure or seniority). Each episode is carefully curated and edited to provide concise, actionable, authoritative information about software best practices and developer tools. After an episode is published, it is posted to Google bathrooms around the world, and is also available to read online internally at Google. TotT episodes often become a canonical source for helping far-flung teams standardize their software development tools and practices. Because Every Superhero Has An Origin Story TotT began as a bottom-up approach to drive a culture change. The year was 2006 and Google was experiencing rapid growth and huge challenges: there were many costly bugs and rolled-back releases. A small group of engineers, members of the so-called Testing Grouplet, pass

## SMURF: Beyond the Test Pyramid

DevFeed: [SMURF: Beyond the Test Pyramid](<https://devfeed.tech/articles/smurf-beyond-the-test-pyramid-23861.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/10/smurf-beyond-test-pyramid.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-10-15T12:22:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [Mocking](<https://devfeed.tech/topics/mocking.md>)

Tags: [adam-bender](<https://devfeed.tech/tags/adam-bender.md>), [article](<https://devfeed.tech/tags/article.md>), [dependency](<https://devfeed.tech/tags/dependency.md>), [flaky](<https://devfeed.tech/tags/flaky.md>), [google](<https://devfeed.tech/tags/google.md>), [integration](<https://devfeed.tech/tags/integration.md>), [maintainability](<https://devfeed.tech/tags/maintainability.md>), [memory](<https://devfeed.tech/tags/memory.md>), [production](<https://devfeed.tech/tags/production.md>), [resources](<https://devfeed.tech/tags/resources.md>), [speed](<https://devfeed.tech/tags/speed.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>), [tott](<https://devfeed.tech/tags/tott.md>), [unit-tests](<https://devfeed.tech/tags/unit-tests.md>)

### AI overview

This Google Testing on the Toilet article explains why the conventional test pyramid is insufficient for growing test suites. It introduces the SMURF mnemonic--Speed, Maintainability, Utilization, Reliability, and Fidelity--as a framework for balancing testing trade-offs.

### Source excerpt

This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Adam Bender The test pyramid is the canonical heuristic for guiding test suite evolution. It conveys a simple message - prefer more unit tests than integration tests, and prefer more integration tests than end-to-end tests. While useful, the test pyramid lacks the details you need as your test suite grows and you face challenging trade-offs. To scale your test suite, go beyond the test pyramid. The SMURF mnemonic is an easy way to remember the tradeoffs to consider when balancing your test suite: Speed: Unit tests are faster than other test types and can be run more often--you'll catch problems sooner. Maintainability: The aggregated cost of debugging and maintaining tests (of all types) adds up quickly. A larger system under test has more code, and thus greater exposure to dependency churn and requirement drift which, in turn, creates more maintenance work. Utilization: Tests that use fewer resources (memory, disk, CPU) cost less to run. A good test suite optimizes resource utilization so that it does not grow super-linearly with the number of tests. Unit tests usually have better utilization characteristics, often because they use test doubles or only involve limited parts of a system. Reliability: Reliable tests only fail when an actual problem has been discovered. Sorting through flaky tests for problems wastes developer time and costs resources in rerunning the tests. As the size of a system and its corresponding tests grow, non-determinism (and thus, flakiness) creeps in, and your test suite is more likely to become unreliable. Fidelity: High-fidelity tests come closer to approximating real operating conditions (e.g., real databases or traffic loads) and better predict the behavior of our production systems. Integration and end-to-end tests can better reflect realistic conditions, while unit

## Write Change-Resilient Code With Domain Objects

DevFeed: [Write Change-Resilient Code With Domain Objects](<https://devfeed.tech/articles/write-change-resilient-code-with-domain-objects-23860.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/09/write-change-resilient-code-with-domain.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-09-04T12:56:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [implementation](<https://devfeed.tech/topics/implementation.md>), [maintenance](<https://devfeed.tech/topics/maintenance.md>), [interfaces](<https://devfeed.tech/topics/interfaces.md>)

Tags: [amy-fu](<https://devfeed.tech/tags/amy-fu.md>), [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [interfaces](<https://devfeed.tech/tags/interfaces.md>), [maintenance](<https://devfeed.tech/tags/maintenance.md>), [tott](<https://devfeed.tech/tags/tott.md>), [writing-code](<https://devfeed.tech/tags/writing-code.md>)

### AI overview

This Google Code Health article explains how domain objects--classes and interfaces that model a product's fundamental ideas--can make code more resilient to changing requirements. A gPizza example shows how modeling shared concepts can reduce the maintenance burden caused by adding requirement-specific methods.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. By Amy Fu Although a product's requirements can change often, its fundamental ideas usually change slowly. This leads to an interesting insight: if we write code that matches the fundamental ideas of the product, it will be more likely to survive future product changes. Domain objects are building blocks (such as classes and interfaces) in our code that match the fundamental ideas of the product. Instead of writing code to match the desired behavior for the product's requirements ("configure text to be white"), we match the underlying idea ("text color settings"). For example, imagine you're part of the gPizza team, which sells tasty, fresh pizzas to feed hungry Googlers. Due to popular demand, your team has decided to add a delivery service. Without domain objects, the quickest path to pizza delivery is to simply create a deliverPizza method: public class DeliveryService { public void deliverPizza(List<Pizza> pizzas) { ... } } Although this works well at first, what happens if gPizza expands its offerings to other foods? You could add a new method: public void deliverWithDrinks(List<Pizza> pizzas, List<Drink> drinks) { ... } But as your list of requirements grows (snacks, sweets, etc.), you'll be stuck adding more and more methods. How can you change your initial implementation to avoid this continued maintenance burden? You could add a domain object that models the product's ideas, instead of its requirements: A use case is a specific behavior that helps the product satisfy its business requirements. (In this case, "Deliver pizzas so we make more money".) A domain object represents a common idea that is shared by several similar use cases. To identify the appropriate domain object, ask yourself: What related use cases does the produc

## Less Is More: Principles for Simple Comments

DevFeed: [Less Is More: Principles for Simple Comments](<https://devfeed.tech/articles/less-is-more-principles-for-simple-comments-23859.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/08/less-is-more-principles-for-simple.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-08-21T12:38:00Z

Content type: article

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Documentation](<https://devfeed.tech/topics/documentation.md>), [Testing](<https://devfeed.tech/topics/testing.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [code-comments](<https://devfeed.tech/tags/code-comments.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [cognitive-load](<https://devfeed.tech/tags/cognitive-load.md>), [david-bendory](<https://devfeed.tech/tags/david-bendory.md>), [improvements](<https://devfeed.tech/tags/improvements.md>), [reduce](<https://devfeed.tech/tags/reduce.md>), [tott](<https://devfeed.tech/tags/tott.md>), [writing](<https://devfeed.tech/tags/writing.md>)

### AI overview

This article presents principles for writing simple, maintainable code comments. It recommends reviewing comments separately from code, making them self-contained, including only essential information, and using links to bugs or documentation for follow-up context.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. By David Bendory Simplicity is the ultimate sophistication. -- Leonardo da Vinci You're staring at a wall of code resembling a Gordian knot of Klingon. What's making it worse? A sea of code comments so long that you'd need a bathroom break just to read them all! Let's fix that. Adopt the mindset of someone unfamiliar with the project to ensure simplicity. One approach is to separate the process of writing your comments from reviewing them; proofreading your comments without code context in mind helps ensure they are clear and concise for future readers. Use self-contained comments to clearly convey intent without relying on the surrounding code for context. If you need to read the code to understand the comment, you've got it backwards! Not self-contained; requires reading the code Suggested alternative // Respond to flashing lights in // rearview mirror. // Pull over for police and/or yield to // emergency vehicles. while flashing_lights_in_rearview_mirror() { if !move_to_slower_lane() { stop_on_shoulder(); } } Include only essential information in the comments and leverage external references to reduce cognitive load on the reader. For comments suggesting improvements, links to relevant bugs or docs keep comments concise while providing a path for follow-up. Note that linked docs may be inaccessible, so use judgment in deciding how much context to include directly in the comments. Too much potential improvement in the comment Suggested alternative // The local bus offers good average- // case performance. Consider using // the subway which may be faster // depending on factors like time of // day, weather, etc. // TODO: Consider various factors to // present the best transit option. // See issuetracker.fake/bus-vs-subway commute_by_lo

## In Praise of Small Pull Requests

DevFeed: [In Praise of Small Pull Requests](<https://devfeed.tech/articles/in-praise-of-small-pull-requests-23858.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/07/in-praise-of-small-pull-requests.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-07-16T13:00:00Z

Content type: article

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [pull-requests](<https://devfeed.tech/topics/pull-requests.md>), [Code review](<https://devfeed.tech/topics/code-review.md>), [engineering-culture](<https://devfeed.tech/topics/engineering-culture.md>)

Tags: [code-health](<https://devfeed.tech/tags/code-health.md>), [code-review](<https://devfeed.tech/tags/code-review.md>), [elliotte-rusty-harold](<https://devfeed.tech/tags/elliotte-rusty-harold.md>), [merge](<https://devfeed.tech/tags/merge.md>), [pull-requests](<https://devfeed.tech/tags/pull-requests.md>), [review](<https://devfeed.tech/tags/review.md>), [tott](<https://devfeed.tech/tags/tott.md>), [version-control](<https://devfeed.tech/tags/version-control.md>)

### AI overview

This Google Testing on the Toilet Code Health post explains why pull requests should be small and focused on one self-contained change. It says smaller pull requests are easier and faster to review, make mistakes easier to detect, simplify debugging and rollback, reduce merge conflicts, improve pull request descriptions and revision history, and can increase code coverage.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. By Elliotte Rusty Harold Note: A "pull request" refers to one self-contained change that has been submitted to version control or which is undergoing code review. At Google, this is referred to as a"CL", which is short for "changelist". Prefer small, focused pull requests that do exactly one thing each. Why? Several reasons: Small pull requests are easier to review. A mistake in a focused pull request is more obvious. In a 40 file pull request that does several things, would you notice that one if statement had reversed the logic it should have and was using true instead of false? By contrast, if that if block and its test were the only things that changed in a pull request, you'd be a lot more likely to catch the error. Small pull requests can be reviewed quickly. A reviewer can often respond quickly by slipping small reviews in between other tasks. Larger pull requests are a big task by themselves, often waiting until the reviewer has a significant chunk of time. If something does go wrong and your continuous build breaks on a small pull request, the small size makes it much easier to figure out exactly where the mistake is. They are also easier to rollback if something goes wrong. By virtue of their size, small pull requests are less likely to conflict with other developers' work. Merge conflicts are less frequent and easier to resolve. If you've made a critical error, it saves a lot of work when the reviewer can point this out after you've only gone a little way down the wrong path. Better to find out after an hour than after several weeks. Pull request descriptions are more accurate when pull requests are focused on one task. The revision history becomes easier to read. Small pull requests can lead to increased code coverage becau

## Don't DRY Your Code Prematurely

DevFeed: [Don't DRY Your Code Prematurely](<https://devfeed.tech/articles/don-t-dry-your-code-prematurely-23856.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/05/dont-dry-your-code-prematurely.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-05-28T14:20:00Z

Content type: opinion

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Testing](<https://devfeed.tech/topics/testing.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [dan-maksimovich](<https://devfeed.tech/tags/dan-maksimovich.md>), [series](<https://devfeed.tech/tags/series.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

The article explains why applying DRY principles too rigidly can create premature abstractions. It recommends distinguishing truly redundant code from superficially similar code whose behavior may need to evolve independently.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. By Dan Maksimovich Many of us have been told the virtues of "Don't Repeat Yourself" or DRY. Pause and consider: Is the duplication truly redundant or will the functionality need to evolve independently over time? Applying DRY principles too rigidly leads to premature abstractions that make future changes more complex than necessary. Consider carefully if code is truly redundant or just superficially similar. While functions or classes may look the same, they may also serve different contexts and business requirements that evolve differently over time. Think about how the functions' purpose holds with time, not just about making the code shorter. When designing abstractions, do not prematurely couple behaviors that may evolve separately in the longer term. When does introducing an abstraction harm our code? Let's consider the following code: # Premature DRY abstraction assuming # uniform rules, limiting entity- # specific changes. class DeadlineSetter: def __init__(self, entity_type): self.entity_type = entity_type def set_deadline(self, deadline): if deadline <= datetime.now(): raise ValueError( "Date must be in the future") task = DeadlineSetter("task") task.set_deadline( datetime(2024, 3, 12)) payment = DeadlineSetter("payment") payment.set_deadline( datetime(2024, 3, 18)) # Repetitive but allows for clear, # entity-specific logic and future # changes. def set_task_deadline(task_deadline): if task_deadline <= datetime.now(): raise ValueError( "Date must be in the future") def set_payment_deadline( payment_deadline): if payment_deadline <= datetime.now(): raise ValueError( "Date must be in the future") set_task_deadline( datetime(2024, 3, 12)) set_payment_deadline( datetime(2024, 3, 18)) The approach on the right seems to violate the

## Avoid the Long Parameter List

DevFeed: [Avoid the Long Parameter List](<https://devfeed.tech/articles/avoid-the-long-parameter-list-23855.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/05/avoid-long-parameter-list.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-05-20T13:42:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Java](<https://devfeed.tech/topics/java.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Python](<https://devfeed.tech/topics/python.md>)

Tags: [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [class](<https://devfeed.tech/tags/class.md>), [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [data-class](<https://devfeed.tech/tags/data-class.md>), [gene-volovich](<https://devfeed.tech/tags/gene-volovich.md>), [google](<https://devfeed.tech/tags/google.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [language](<https://devfeed.tech/tags/language.md>), [list](<https://devfeed.tech/tags/list.md>), [parameter](<https://devfeed.tech/tags/parameter.md>), [post](<https://devfeed.tech/tags/post.md>), [python](<https://devfeed.tech/tags/python.md>), [series](<https://devfeed.tech/tags/series.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This Google Code Health article explains how long parameter lists make method calls difficult to understand and maintain. It recommends grouping related parameters into meaningful value objects, with language-specific options including Java records, Kotlin data classes, C++ option structs, Python keyword arguments and defaults, and the Java Builder pattern.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. By Gene Volovich Have you seen code like this? void transform(String fileIn, String fileOut, String separatorIn, String separatorOut); This seems simple enough, but it can be difficult to remember the parameter ordering. It gets worse if you add more parameters (e.g., to specify the encoding, or to email the resulting file): void transform(String fileIn, String fileOut, String separatorIn, String separatorOut, String encoding, String mailTo, String mailSubject, String mailTemplate); To make the change, will you add another (overloaded) transform method? Or add more parameters to the existing method, and update every single call to transform? Neither seems satisfactory. One solution is to encapsulate groups of the parameters into meaningful objects. The CsvFile class used here is a "value object" -- simply a holder for the data. class CsvFile { CsvFile(String filename, String separator, String encoding) { ... } String filename() { return filename; } String separator() { return separator; } String encoding() { return encoding; } } // ... and do the same for the EmailMessage class void transform(CsvFile src, CsvFile target, EmailMessage resultMsg) { ... } How to define a value object varies by language. For example, in Java, you can use a record class, which is available in Java 16+ (for older versions of Java, you can use AutoValue to generate code for the value object); in Kotlin, you can use a data class; in C++, you can use an option struct. Using a value object this way may still result in a long parameter list when instantiating it. Solutions for this vary by language. For example, in Python, you can use keyword arguments and default parameter values to shorten the parameter list; in Java, one option is to use the Builder pattern, wh

## Test Failures Should Be Actionable

DevFeed: [Test Failures Should Be Actionable](<https://devfeed.tech/articles/test-failures-should-be-actionable-23857.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/05/test-failures-should-be-actionable.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-05-06T13:26:00Z

Content type: article

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [Unit testing](<https://devfeed.tech/topics/unit-testing.md>), [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>), [site-reliability-engineering](<https://devfeed.tech/topics/site-reliability-engineering.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Pytest](<https://devfeed.tech/topics/pytest.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [best-practices](<https://devfeed.tech/tags/best-practices.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [pytest](<https://devfeed.tech/tags/pytest.md>), [site-reliability-engineering](<https://devfeed.tech/tags/site-reliability-engineering.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [testing](<https://devfeed.tech/tags/testing.md>), [titus-winters](<https://devfeed.tech/tags/titus-winters.md>), [tott](<https://devfeed.tech/tags/tott.md>), [unit-testing](<https://devfeed.tech/tags/unit-testing.md>)

### AI overview

The article argues that unit test failures should be actionable: developers should be able to start investigating using only the test name and failure messages. It recommends precise invariants and assertion-library matchers, illustrating the point with a C++ status-check example.

### Source excerpt

This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Titus Winters There are a lot of rules and best practices around unit testing. There are many posts on this blog; there is deeper material in the Software Engineering at Google book; there is specific guidance for every major language; there is guidance on test frameworks, test naming, and dozens of other test-related topics. Isn't this excessive? Good unit tests contain several important properties, but you could focus on a key principle: Test failures should be actionable. When a test fails, you should be able to begin investigation with nothing more than the test's name and its failure messages--no need to add more information and rerun the test. Effective use of unit test frameworks and assertion libraries (JUnit, Truth, pytest, GoogleTest, etc.) serves two important purposes. Firstly, the more precisely we express the invariants we are testing, the more informative and less brittle our tests will be. Secondly, when those invariants don't hold and the tests fail, the failure info should be immediately actionable. This meshes well with Site Reliability Engineering guidance on alerting. Consider this example of a C++ unit test of a function returning an absl::Status (an Abseil type that returns either an "OK" status or one of a number of different error codes): EXPECT_TRUE(LoadMetadata().ok()); EXPECT_OK(LoadMetadata()); Sample failure output load_metadata_test.cc:42: Failure Value of: LoadMetadata().ok() Expected: true Actual: false load_metadata_test.cc:42: Failure Value of: LoadMetadata() Expected: is OK Actual: NOT_FOUND: /path/to/metadata.bin If the test on the left fails, you have to investigate why the test failed; the test on the right immediately gives you all the available detail, in this case because of a more precise GoogleTest matcher. Here are some other posts on this blog that emp

## Simplify Complex Boolean Expressions with Meaningful Intermediate Variables

DevFeed: [Simplify Complex Boolean Expressions with Meaningful Intermediate Variables](<https://devfeed.tech/articles/isbooleantoolongandcomplex-23853.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/04/isbooleantoolongandcomplex.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-04-25T13:14:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Testing](<https://devfeed.tech/topics/testing.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [expression](<https://devfeed.tech/tags/expression.md>), [intermediate](<https://devfeed.tech/tags/intermediate.md>), [post](<https://devfeed.tech/tags/post.md>), [quality](<https://devfeed.tech/tags/quality.md>), [series](<https://devfeed.tech/tags/series.md>), [tott](<https://devfeed.tech/tags/tott.md>), [yiming-sun](<https://devfeed.tech/tags/yiming-sun.md>)

### AI overview

This Code Health article explains how to make complex Boolean expressions easier to understand. It recommends extracting conditions into well-named variables and then grouping details into intermediate Booleans that represent single, well-defined qualities, without changing the business logic.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. By Yiming Sun You may have come across some complex, hard-to-read Boolean expressions in your codebase and wished they were easier to understand. For example, let's say we want to decide whether a pizza is fantastic: // Decide whether this pizza is fantastic. if ((!pepperoniService.empty() || sausages.size() > 0) && (useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO)) && hasCheese()) { ... } A first step toward improving this is to extract the condition into a well-named variable: boolean isPizzaFantastic = (!pepperoniService.empty() || sausages.size() > 0) && (useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO)) && hasCheese(); if (isPizzaFantastic) { ... } However, the Boolean expression is still too complex. It's potentially confusing to calculate the value of isPizzaFantastic from a given set of inputs. You might need to grab a pen and paper, or start a server locally and set breakpoints. Instead, try to group the details into intermediate Booleans that provide meaningful abstractions. Each Boolean below represents a single well-defined quality, and you no longer need to mix && and || within an expression. Without changing the business logic, you've made it easier to see how the Booleans relate to each other: boolean hasGoodMeat = !pepperoniService.empty() || sausages.size() > 0; boolean hasGoodVeggies = useOnionFlag.get() || hasMushroom(ENOKI, PORTOBELLO); boolean isPizzaFantastic = hasGoodMeat && hasGoodVeggies && hasCheese(); Another option is to hide the logic in a separate method. This also offers the possibility of early returns using guard clauses, further reducing the need to keep track of intermediate states: boolean isPizzaFantastic() { if (!hasCheese()) { return false; } if (pepperoniService.empty() && sausages.size()

## How I Learned To Stop Writing Brittle Tests and Love Expressive APIs

DevFeed: [How I Learned To Stop Writing Brittle Tests and Love Expressive APIs](<https://devfeed.tech/articles/how-i-learned-to-stop-writing-brittle-tests-and-love-expressive-apis-23852.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/04/how-i-learned-to-stop-writing-brittle.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-04-18T12:50:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Code](<https://devfeed.tech/topics/code.md>), [API](<https://devfeed.tech/topics/api.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [code](<https://devfeed.tech/tags/code.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>), [titus-winters](<https://devfeed.tech/tags/titus-winters.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This article explains how brittle tests can fail because of irrelevant implementation details, such as error-message changes, metadata ordering, or mock call ordering. It recommends expressive test APIs that state the properties that matter, illustrated with a C++ GoogleTest example using UnorderedElementsAre instead of order-dependent ElementsAre.

### Source excerpt

This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Titus Winters A valuable but challenging property for tests is "resilience," meaning a test should only fail when something important has gone wrong. However, an opposite property may be easier to see: A "brittle" test is one that fails not for real problems that would break in production, but because the test itself is fragile for innocuous reasons. Error messages, changing the order of metadata headers in a web request, or the order of calls to a heavily-mocked dependency can often cause a brittle test to fail. Expressive test APIs are a powerful tool in the fight against brittle, implementation-detail heavy tests. A test written with IsSquare(output) is more expressive (and less brittle) than a test written with details such as JsonEquals(.width = 42, .length = 42), in cases where the size of the square is irrelevant. Similar expressive designs might include unordered element matching for hash containers, metadata comparisons for photos, and activity logs in processing objects, just to name a few. As an example, consider this C++ test code: absl::flat_hash_set<int> GetValuesFromConfig(const Config&); TEST(ConfigValues, DefaultConfigsArePrime) { // Note the strange order of these values. BAD CODE, DON'T DO THIS! EXPECT_THAT(GetValuesFromConfig(Config()), ElementsAre(29, 17, 31)); } The reliance on hash ordering makes this test brittle, preventing improvements to the API being tested. A critical part of the fix to the above code was to provide better test APIs that allowed engineers to more effectively express the properties that mattered. Thus we added UnorderedElementsAre to the GoogleTest test framework and refactored brittle tests to use that: TEST(ConfigValues, DefaultConfigsArePrimeAndOrderDoesNotMatter) { EXPECT_THAT(GetValuesFromConfig(Config()), UnorderedElementsAre(17, 29, 31)); } It's

## Prefer Narrow Assertions in Unit Tests

DevFeed: [Prefer Narrow Assertions in Unit Tests](<https://devfeed.tech/articles/prefer-narrow-assertions-in-unit-tests-23854.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/04/prefer-narrow-assertions-in-unit-tests.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-04-04T12:47:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [Database](<https://devfeed.tech/topics/database.md>), [Front end](<https://devfeed.tech/topics/frontend.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [bugs](<https://devfeed.tech/tags/bugs.md>), [frontend](<https://devfeed.tech/tags/frontend.md>), [kai-kent](<https://devfeed.tech/tags/kai-kent.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>), [tott](<https://devfeed.tech/tags/tott.md>), [unit-tests](<https://devfeed.tech/tags/unit-tests.md>)

### AI overview

The article explains why broad equality assertions can make unit tests brittle by checking unrelated behavior. It recommends narrow assertions that verify only the relevant field or behavior, while reserving full-equality tests for cases that intentionally cover all related behaviors. It also briefly applies the principle to frontend unit tests.

### Source excerpt

This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. by Kai Kent Your project is adding a loyalty promotion feature, so you add a new column CREATION_DATE to the ACCOUNT table. Suddenly the test below starts failing. Can you spot the problem? TEST_F(AccountTest, UpdatesBalanceAfterWithdrawal) { ASSERT_OK_AND_ASSIGN(Account account, database.CreateNewAccount(/*initial_balance=*/5000)); ASSERT_OK(account.Withdraw(3000)); const Account kExpected = { .balance = 2000, /* a handful of other fields */ }; EXPECT_EQ(account, kExpected); } You forgot to update the test for the newly added column; but the test also has an underlying problem: It checks for full equality of a potentially complex object, and thus implicitly tests unrelated behaviors. Changing anything in Account, such as adding or removing a field, will cause all the tests with a similar pattern to fail. Broad assertions are an easy way to accidentally create brittle tests - tests that fail when anything about the system changes, and need frequent fixing even though they aren't finding real bugs. Instead, the test should use narrow assertions that only check the relevant behavior. The example test should be updated to only check the relevant field account.balance: TEST_F(AccountTest, UpdatesBalanceAfterWithdrawal) { ASSERT_OK_AND_ASSIGN(Account account, database.CreateNewAccount(/*initial_balance=*/5000)); ASSERT_OK(account.Withdraw(3000)); EXPECT_EQ(account.balance, 2000); } Broad assertions should only be used for unit tests that care about all of the implicitly tested behaviors, which should be a small minority of unit tests. Prefer to have at most one such test that checks for full equality of a complex object for the common case, and use narrow assertions for all other cases. Similarly, when writing frontend unit tests, use one screenshot diff test to verify the layout of your UI, but test ind

## Naming Code Clearly: Practical Tips for More Readable Identifiers and APIs

DevFeed: [Naming Code Clearly: Practical Tips for More Readable Identifiers and APIs](<https://devfeed.tech/articles/what-s-in-a-name-23851.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/03/whats-in-name.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-03-26T12:34:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Computer science](<https://devfeed.tech/topics/computer-science.md>)

Tags: [abstraction](<https://devfeed.tech/tags/abstraction.md>), [adam-raider](<https://devfeed.tech/tags/adam-raider.md>), [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [identifier](<https://devfeed.tech/tags/identifier.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [interface](<https://devfeed.tech/tags/interface.md>), [tips](<https://devfeed.tech/tags/tips.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

This Code Health post explains why unclear identifiers and interfaces increase cognitive load and make code harder to read. It offers naming guidance, including describing behavior, considering the cost of renaming, revealing intent, and preferring precise names.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. by Adam Raider "There are only two hard things in computer science: cache invalidation and naming things." --Phil Karlton Have you ever read an identifier only to realize later it doesn't do what you expected? Or had to read the implementation in order to understand an interface? These indirections eat up our cognitive bandwidth and make our work more difficult. We spend far more time reading code than we do writing it; thoughtful names can save the reader (and writer) a lot of time and frustration. Here are some naming tips: Spend time considering names--it's worth it. Don't default to the first name that comes to mind. The more public the name, the more expensive it is to change. Past a certain scale, names become infeasible to change, especially for APIs. Pay attention to a name in proportion to the cost of renaming it later. If you're feeling stuck, consider running a new name by a teammate. Describe behavior. Encourage naming based on what functions do rather than when the functions are called. Avoid prefixes like "handle" or "on" as they describe when and provide no added meaning: button.listen('click', handleClick) button.listen('click', addItemToCart) Reveal intent with a contextually appropriate level of abstraction: High-abstraction functions describe the what and operate on high-level types. Lower-abstraction functions describe the how and operate on lower-level types. For example, logout might call into clearUserToken, and recordWithCamera might call into parseStreamBytes. Prefer unique, precise names. Are you frequently asking for the UserManager? Manager, Util, and similar suffixes are a common but imprecise naming convention. What does it do? It manages! If you're struggling to come up with a more precise name, consider sp

## Increase Test Fidelity By Avoiding Mocks

DevFeed: [Increase Test Fidelity By Avoiding Mocks](<https://devfeed.tech/articles/increase-test-fidelity-by-avoiding-mocks-23850.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2024/02/increase-test-fidelity-by-avoiding-mocks.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2024-02-27T18:43:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Testing](<https://devfeed.tech/topics/testing.md>), [Mocking](<https://devfeed.tech/topics/mocking.md>), [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>), [Database](<https://devfeed.tech/topics/database.md>), [API](<https://devfeed.tech/topics/api.md>)

Tags: [andrew-trenk](<https://devfeed.tech/tags/andrew-trenk.md>), [article](<https://devfeed.tech/tags/article.md>), [bugs](<https://devfeed.tech/tags/bugs.md>), [code](<https://devfeed.tech/tags/code.md>), [database](<https://devfeed.tech/tags/database.md>), [dillon-bly](<https://devfeed.tech/tags/dillon-bly.md>), [in-memory-database](<https://devfeed.tech/tags/in-memory-database.md>), [software](<https://devfeed.tech/tags/software.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [testing](<https://devfeed.tech/tags/testing.md>), [tests](<https://devfeed.tech/tags/tests.md>), [tott](<https://devfeed.tech/tags/tott.md>), [unit-tests](<https://devfeed.tech/tags/unit-tests.md>)

### AI overview

This Google Testing on the Toilet article explains that test fidelity is higher when tests use the real dependency implementation. If that is impractical, it recommends using a fake, such as an in-memory database, and using a mock only when neither a real implementation nor a fake is suitable. Mocks can reduce fidelity because their inline behavior may diverge from the real dependency.

### Source excerpt

This article was adapted from a Google Testing on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Andrew Trenk and Dillon Bly Replacing your code's dependencies with mocks can make unit tests easier to write and faster to run. However, among other problems, using mocks can lead to tests that are less effective at catching bugs. The fidelity of a test refers to how closely the behavior of the test resembles the behavior of the production code. A test with higher fidelity gives you higher confidence that your code will work properly. When specifying a dependency to use in a test, prefer the highest-fidelity option. Learn more in the Test Doubles chapter of the Software Engineering at Google book. Try to use the real implementation. This provides the most fidelity, because the code in the implementation will be executed in the test. There may be tradeoffs when using a real implementation: they can be slow, non-deterministic, or difficult to instantiate (e.g., it connects to an external server). Use your judgment to decide if a real implementation is the right choice. Use a fake if you can't use the real implementation. A fake is a lightweight implementation of an API that behaves similarly to the real implementation, e.g., an in-memory database. A fake ensures a test has high fidelity, but takes effort to write and maintain; e.g., it needs its own tests to ensure that it conforms to the behavior of the real implementation. Typically, the owner of the real implementation creates and maintains the fake. Use a mock if you can't use the real implementation or a fake. A mock reduces fidelity, since it doesn't execute any of the actual implementation of a dependency; its behavior is specified inline in a test (a technique known as stubbing), so it may diverge from the behavior of the real implementation. Mocks provide a basic level of confidence that your code works properly, and can be especially use

## How to Write Code Comments That Improve Readability

DevFeed: [How to Write Code Comments That Improve Readability](<https://devfeed.tech/articles/let-code-speak-for-itself-23849.md>)

Original publisher: [Read original article](<http://testing.googleblog.com/2023/12/let-code-speak-for-itself.html>)

Author: Google Testing Bloggers (noreply@blogger.com)

Published: 2023-12-12T16:06:00Z

Content type: tutorial

Language: en

Sources: [Google Testing Blog](<https://devfeed.tech/sources/google-testing-blog.md>)

Topics: [Code](<https://devfeed.tech/topics/code.md>), [Documentation](<https://devfeed.tech/topics/documentation.md>), [implementation](<https://devfeed.tech/topics/implementation.md>)

Tags: [api-documentation](<https://devfeed.tech/tags/api-documentation.md>), [code](<https://devfeed.tech/tags/code.md>), [code-health](<https://devfeed.tech/tags/code-health.md>), [documentation](<https://devfeed.tech/tags/documentation.md>), [francois-aube](<https://devfeed.tech/tags/francois-aube.md>), [guide](<https://devfeed.tech/tags/guide.md>), [readability](<https://devfeed.tech/tags/readability.md>), [shiva-garg](<https://devfeed.tech/tags/shiva-garg.md>), [tott](<https://devfeed.tech/tags/tott.md>)

### AI overview

The article offers practical guidance for writing maintainable code: use comments to explain why an approach is taken, choose descriptive identifiers, document function purpose and meaning, and avoid comments about implementation details that may change.

### Source excerpt

This is another post in our Code Health series. A version of this post originally appeared in Google bathrooms worldwide as a Google Testing on the Toilet episode. You can download a printer-friendly version to display in your office. by Shiva Garg and Francois Aube Comments can be invaluable for understanding and maintaining a code base. But excessive comments in code can become unhelpful clutter full of extraneous and/or outdated detail. Comments that offer useless (or worse, obsolete) information hurt readability. Here are some tips to let your code speak for itself: Write comments to explain the "why" behind a certain approach in code. The comment below has two good reasons to exist: documenting non-obvious behavior and answering a question that a reader is likely to have (i.e. why doesn't this code render directly on the screen?): // Eliminate flickering by rendering the next frame off-screen and swapping into the // visible buffer. RenderOffScreen(); SwapBuffers(); Use well-named identifiers to guide the reader and reduce the need for comments: // Payout should not happen if the user is // in an ineligible country. std::unordered_set<std::string> ineligible = {"Atlantis", "Utopia"}; if (!ineligible.contains(country)) { Payout(user.user_id); } if (IsCountryEligibleForPayout(country)) { Payout(user.user_id); } Write function comments (a.k.a. API documentation) that describe intended meaning and purpose, not implementation details. Choose unambiguous function signatures that callers can use without reading any documentation. Don't explain inner details that could change without affecting the contract with the caller: // Reads an input string containing either a // number of milliseconds since epoch or an // ISO 8601 date and time. Invokes the // Sole, Laces, and ToeCap APIs, then // returns an object representing the Shoe // available then or nullptr if none were. Shoe* ModelAvailableAt(char* time); // Returns the Shoe that was available for // purchase at `time`

[Next page](<https://devfeed.tech/tags/tott.md?cursor=WyIyMDIzLTEyLTEyVDE2OjA2OjAwKzAwOjAwIiwgIjgwMmUwZmZkLTkxZWMtNDhhNS1hNDgyLWE2ODFjZGIxY2U2OSJd>)