Google Testing Blog
フィード

Arrange Your Code to Communicate Data Flow
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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, pas...
3ヶ月前

Tech on the Toilet: Driving Software Excellence, One Bathroom Break at a Time
Google Testing Blog
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 volunt...
4ヶ月前

SMURF: Beyond the Test Pyramid
Google Testing Blog
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 dr...
6ヶ月前

Write Change-Resilient Code With Domain Objects
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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, imag...
7ヶ月前

Less Is More: Principles for Simple Comments
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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 comment...
8ヶ月前

In Praise of Small Pull Requests
Google Testing Blog
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...
9ヶ月前

Don't DRY Your Code Prematurely
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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’...
10ヶ月前

Avoid the Long Parameter List
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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 ano...
1年前

Test Failures Should Be Actionable
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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 mess...
1年前

isBooleanTooLongAndComplex
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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 = (!pepperoniS...
1年前

How I Learned To Stop Writing Brittle Tests and Love Expressive APIs
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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, implementa...
1年前

Prefer Narrow Assertions in Unit Tests
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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 ch...
1年前

What’s in a Name?
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } 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: Spen...
1年前

Increase Test Fidelity By Avoiding Mocks
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } @media (max-width: 480px), (max-height: 480px) { .post-content table, .post-content td { width: auto !important } } 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 ...
1年前

Let Code Speak for Itself
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } td{ white-space: nowrap; } } 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 rende...
1年前

Exceptional Exception Handling
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Have you ever seen huge exception-handling blocks? Here is an example in Java, although you may have seen similar problems in Python, TypeScript, Kotlin, or any language that supports exceptions. Let's assume we are calling bakePizza() to bake a pizza, and it can be overbaked, throwing a PizzaOverbakedException. class PizzaOverbakedException extends Exception {}; void bakePizza () throws PizzaOverbakedException {}; try { // 100+ lines of code to prepare pizza ingredients. ... bakePizza(); // Another 100+ lines of code to deliver pizza to a customer. ... } catch (Exception e) { throw new IllegalStateException(); // Root cause ignored while thro...
1年前

Clean Up Code Cruft
Google Testing Blog
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 Per Jacobsson The book Clean Code discusses a camping rule that is good to keep in the back of your mind when writing code: Leave the campground cleaner than you found it So how does that fit into software development? The thinking is this: When you make changes to code that can potentially be improved, try to make it just a little bit better. This doesn't necessarily mean you have to go out of your way to do huge refactorings. Changing something small can go a long way: Rename a variable to something more descriptive. Break apart a huge function into a few logical pieces. Fix a lint warning. Bring an outdated comment up to date. Extract duplicated lines to a function. Write a unit test for an untested function. Whatever other itch you f...
1年前

Write Clean Code to Reduce Cognitive Load
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Andrew Trenk Do you ever read code and find it hard to understand? You may be experiencing cognitive load! Cognitive load refers to the amount of mental effort required to complete a task. When reading code, you have to keep in mind information such as values of variables, conditional logic, loop indices, data structure state, and interface contracts. Cognitive load increases as code becomes more complex. People can typically hold up to 5–7 separate pieces of information in their short-term memory (source); code that involves more information than that can be difficult to understand. Cognitive load is often higher for other people reading code you wrote than it is for...
1年前

Include Only Relevant Details In Tests
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Dagang Wei What problem in the code below makes the test hard to follow? def test_get_balance(self): settings = BankSettings(FDIC_INSURED, REGULATED, US_BASED) account = Account(settings, ID, BALANCE, ADDRESS, NAME, EMAIL, PHONE) self.assertEqual(account.GetBalance(), BALANCE) The problem is that there is a lot of noise in the account creation code, which makes it hard to tell which details are relevant to the assert statement. But going from one extreme to the other can also make the test hard to follow: def test_get_balance(self): account = _create_account() self.assertEqual(account.GetBalance(), BALANCE) Now the problem is that critical details are hidden in the _create_account() helper function, so it’s not o...
1年前

Simplify Your Control Flows
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Jeff Hoy When adding loops and conditionals, even simple code can become difficult to understand. Consider this change: if (commode.HasPreferredCustomer()) { if (commode.HasPreferredCustomer()) { commode.WarmSeat(); commode.WarmSeat(); } else if (commode.CustomerOnPhone()) { commode.ChillSeat(); } } While the above change may seem simple, even adding a single else statement can make the code harder to follow since the complexity of code grows quickly with its size. Below we see the code surrounding the above snippet; the control flow on the right illustrates how much a reader needs to retain: while (commode.StillOccupied()) { if (commode.Ha...
1年前

Improve Readability With Positive Booleans
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Max Kanat-Alexander Reading healthy code should be as easy as reading a book in your native language. You shouldn’t have to stop and puzzle over what a line of code is doing. One small trick that can assist with this is to make boolean checks about something positive rather than about something negative. Here’s an extreme example: if not nodisable_kryponite_shield: devise_clever_escape_plan() else: engage_in_epic_battle() What does that code do? Sure, you can figure it out, but healthy code is not a puzzle, it’s a simple communication. Let’s look at two principles we can use to simplify this code. 1. Name your flags and variables in such a way that they represe...
1年前

Shell Scripts: Stay Small & Simple
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Mandelberg Shell scripts (including Bash scripts) can be convenient for automating simple command line procedures, and they are often better than keeping complicated commands in a single developer's history. However, shell scripts can be hard to understand and maintain, and are typically not as well-supported as other programming languages. Shell scripts have less support for unit testing, and there is likely a lower chance that somebody reading one will be experienced with the language. Python, Go, or other general-purpose languages are often better choices than shell. Shell is convenient for some simple use cases, and the Google shell style guide can help with writing better shell scripts. But it is difficul...
1年前

The Secret to Great Code Reviews: Respect Reviewers' Comments
Google Testing Blog
@media only screen and (max-width: 600px) { .body { overflow-x: auto; } } 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 Marius Latinis You prepared a code change and asked for a review. A reviewer left a comment you disagree with. Are you going to reply that you will not address the comment? When addressing comments for your code reviewed by colleagues, find a solution that makes both you and the reviewer happy. The fact that a reviewer left a comment suggests you may be able to improve the code further. Here are two effective ways to respond: When it’s easy for you to make an improvement, update the code. Improved code benefits future readers and maintainers. You will also avoid a potentially long and emotional debate with a reviewer. If the comment is unclear, ask the reviewer to e...
2年前

Communicate Design Tradeoffs Visually
Google Testing Blog
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 Tim Lyakhovetskiy A goal of any written design or project proposal is to present and evaluate alternatives. However, documents that include multiple solutions can be difficult to read when the qualities of each solution are not clearly expressed. A common approach to simplifying proposals is to use “pros and cons” for each alternative, but this leads to biased writing since the pros and cons may be weighed differently depending on the reader’s priorities. In this example, can you quickly tell how this option would measure up against others? Option 1 - Optimize Shoelace Untangling Wizard in ShoeApp UI Pros Shoelace Untangling Wizard UI will use 10% less CPU Less than one quarter to implement Users will see 100ms less UI lag Cons Security risk (shoelace colors exposed) until ShoeAppBa...
2年前

Else Nuances
Google Testing Blog
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 Sam Lee and Stan Chan If your function exits early in an if statement, using or not using an else clause is equivalent in terms of behavior. However, the proper use of else clauses and guard clauses (lack of else) can help emphasize the intent of the code to the reader. Consider the following guidelines to help you structure your functions: Use a guard clause to handle special cases upfront, so that the rest of the code can focus on the core logic. A guard clause checks a criterion and fails fast or returns early if it is not met, which reduces nesting (see the Reduce Nesting article). def parse_path(path: str) -> Path: if not path: raise ValueError(“path is empty.”) else: # Nested logic here. ... def parse_path(path: str) -> Path: if not...
2年前