Book – Software Engineering at Google

Summary Notes  from the book, Software Engineering at Google

  1. Style Guides and Rules
    1. Auto formatting : Resharper console app.
      1. https://blog.jetbrains.com/dotnet/2018/03/01/code-cleanup-resharper-command-line-tools/
  2. Code Review
    1. Review in 3 aspects
      1. The code will work as intended without error.
      2. If code looks OK to the code owner’s view.
      3. If readability is OK
    2. It might be good to see how many code reviews are made by a developer as it’s unknown effort.
    3. Idea: static analysis -> when build in CI tool, check all warnings and send them to the committer.
    4. Tip: make it small.
  3. Documentation
    1. Wiki type document is hard to get it up to date, and prevent duplicate.
    2. Solution: add the document in source control together with source. Document should have an owner.
    3. Reference Document
      1. Public class/method: must write a comment describing it
      2. Design Doc: write and review before implementing a major project
  4. Testing
    1. Automated testing provide developers change code with confidence.
    2. Adopting automated testing in Google was a cultural change. e.g. orientation class, test certified program, testing on the toilet. -> demonstrating success rather than mandating it.
  5. Unit Testing
    1. Best Practice not to be brittle, but maintainable.
      1. Test only public API
      2. Test state rather than interaction
      3. Clear Test
        1. Make it clear and concise – be clearer over DRY principle.
        2. Test behaviours, not methods
  6. Test Doubles
    1. Realistic tests rather than mocking framework whenever possible: When real logic change, logic in mocking needs to change as well. Consider factors as below.
      1. Execution time
      2. Determinism
      3. Dependency construction
    2. Faking : it can be better off than mocking. e.g. fake DB, fake service
    3. Stubbing: stubbing can be a reasonable technique to use, as long as its usage is constrained so that tests don’t become overly complex.
    4. Prefer state testing over interaction testing
  7. Larger Testing
    1. Larger test is used to cover realistic test that involves multiple dependencies, and systems.
    2. This is needed because Unit Test only cover function level fidelity.
    3. Even for integration test, smaller test is better.
    4. Types of Larger Tests
      1. Functional testing of one or more binaries
      2. Browser and device testing
      3. Performance, load, and stress testing
      4. Deployment configuration testing
      5. Exploratory testing : See if system can resilient on unexpected user input, etc.
      6. A/B diff (regression) testing
      7. User acceptance testing (UAT)
      8. Probers and canary analysis  (in production): Probers is a simple automated smoke test.
      9. Disaster recovery and chaos engineering  (in production): Can do this in the case where system can affordable.
      10. User evaluation (in production)
  8. Deprecation
    1. When the obslete code, depenencies, system became a burden to manage, deprecate it.
    2. Tip: announce it in advance, change the obslete code interface name, stop the old system to see who/what is dependent on it. Provide benefit to move to the new system
    3. Consider the end of product when start builing it. e.g. structure it for a graceful deprecation.
  9. Version Control and Branch Management
    1. Do not use Dev branch. Trunk(master) masted, heavily tested and CI, disable incomplete/untested features at runtime.
    2. Release branch.
    3. One-version rule: developers must not have a choice where to commit, or which version of an existing component to depend upon.
  10. Code Search
  11. Build
    1. Remote Cashing: At Google, many artifacts are served from a cache rather than built from scratch. The cach is shared by many developers.
    2. Artifact based building: each build worker generates artifacts independently and shared through the remote cash. A build worker may depend on the artifacts from the other worker. The dependency graph can be managed in artifact based built, but near impossible in task-based build.
    3. One version rule: the same dependency should be a single version in the system/company.
    4. For a small projects, task based build system will be enough given the overhead of artifact based build system.
    5. One-time cost v.s. ongoing problem.
    6. Automatically managed dependencies can be convenient for small projects, but they’re usually a recipe for Disaster
    7. we enforce a strict One-Version Rule for all third-party dependencies
    8. limiting engineers’ power and flexibility can improve their productivity.
    9. My conclusion: good build system increase developers’ productivity.
  12. Code Review
    1. limiting engineers’ power and flexibility can improve their productivity.
    2. In emergency cases, the author can forcefully commit their change and have it reviewed after commit.
    3. Critique also surfaces the results from builds, tests, and static analyzers, including style checks
    4. Diff features
      1. Syntax highlighting
      2. Cross-references
      3. Intraline diffing
      4. Ignore whitespace
      5. Move detection
    5. Code reiveiw request hook can trigger automated testing, etc and let author know if not not successful
    6. Google greatly values the educational aspects of code review, even though they are more difficult to quantify.
  13. Static Analysis
    1. we generally focus on newly introduced warnings, unless existing warnings are critical.
    2. Key lessions
      1. Focus on developer happiness
        1. Effective false positive (perceived false positive) is important.
        2. Automated fix. e.g. style fix should be an automated fix
        3. Show error or don’t show warning as developers ignore warnings.
      2. Make static analysis a part of the core developer workflow
        1. It’s effective to run static code alanysis when PR raised and report back to author/share with reviwer
      3. Empower users to contribute
        1. Set a feedback loop so that developers provide feedback e.g. Not Useful button.
  14. Dependency Management
    1. Dependency conflict is main concern. i.e. so called diamond dependency. Lib-user may depends on lib-a and lib-b. Both lib-a and lib-b can depend on different version of lib-base each. Lib-user try resolve this by skip forward or backward in version to find compatible version.
    2. “I got it to work” V.S. “this is working in a supported fashion”.
    3.  Solutions
      1. Nothing changes – do not change dependency as far as you can.
      2. Semantic Versioning – major.minor.patch versioning.
      3. Bundled Distribution Models –
      4. Live at Head – Version Control & CI make sure all work
      5. Minimum version selection – select the lowest version possible
  15. Large Scale Changes
    1. Large scale changes prone to create a bug or not successful release
    2. Solution? Create automated tests to cover as much as possible so a large scale changes are covered and rest assured.

 

 

 

 

Leave a comment

Your email address will not be published. Required fields are marked *