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

Frameworks for Coding Confidence

Frameworks for Coding Confidence

As a mobile codebase grows and evolves, it becomes increasingly difficult to make large changes with confidence and speed. Unintended side effects, strange lifecycles, memory leaks, error-cases, and poor code cohesion work together to quickly make a mess of many applications as they grow. This talk will cover some of the techniques Uber has used to allow for changes in a tightly integrated application with confidence, including tools like Dagger 2, static analysis, and annotation processing. We’ll show you how these techniques and tools reinforce each other by demonstrating some concrete anti-patterns that have scaled poorly in the past, as well as how you can combine these new techniques to prevent entire classes of issues in the future.

Luke St.Clair

March 20, 2016
Tweet

Other Decks in Programming

Transcript

  1. • How do you make big changes? • What did

    Uber do? • What worked? • Key point: How do these frameworks and tools work together? Rapid Change A good problem to have
  2. What helps you move fast? Code grows fast Safety/Confidence This

    should be controversial, but consider where development time goes. Compilers Make the compiler do as much for you as possible, then the linter, then testing.
  3. • Very key way to express developer intent. • Where

    do you pass around an integer? • Basis of many other mechanisms for safety. Annotations Much @. So Java.
  4. Validation Natural consequence of annotation More than just IDE hint

    You did the work to tell Java what your code does - why isn’t it helping more? Enforcement What does any of this do? Is it just for the IDE?
  5. RAVE Runtime Annotation Validation Engine Enforces Annotations At runtime, you

    can tell if the state of the program is the state your annotations describe. Enforcement Annotations express intent, annotation processors can help you verify this intent.
  6. Validation (continued) Natural consequence of annotation Can go further First

    step is to boil this down to arbitrary conditions. Can be complicated Most apps have implicit dependencies and data relationships (imperfect APIs).
  7. Infer is a static analysis tool from Facebook that detects

    a pretty wide variety of bugs, from resource/context leaks, to some security violations. The most common use case, however, is for null pointer exceptions. Static Analysis Brought to you by Infer
  8. If a subclass or interface implementation doesn’t return the correct

    nullability, Infer will complain. Subclasses don’t annotate correctly
  9. If you forget to annotate a parameter or a return

    value, Infer will catch this. Infer catches missed annotations Brought to you by Infer
  10. Some engineering is required to use Infer. • Homebrew •

    Gradle • Build times - Caching Infer in Practice
  11. This is sample output from an Infer run. • Multiple

    types of issues. • Automatically analyzes every diff Sample Example Infer Run
  12. • Scopes - high-concept • Dependency resolution - It becomes

    harder to introduce a weird relationship • Helps prevent things like weird circular dependencies • Touch points to help you think about what you’re exposing • If it compiles, it runs. Dagger 2 Compile time scoping and safety
  13. • Easy to add another dependency • Hard to mess

    up the scoping • Can’t mess up the dependency relationship - Well, mostly • There are not many tools to help with lifecycles. Dagger 2 Compile time scoping and safety
  14. • You pay the price for Dagger 2 • Verbosity

    • Testing Dagger 2 Not all easy
  15. Other tools There is so much here Lint Checkstyle Extension

    points help guide consistency in the code base, and make it easy to ensure new code doesn’t accidentally skip some of these important checks. Gradle If you haven’t looked at all possible lint rules, do so. Custom lint is extremely powerful. There’s nothing like a 2 vs 4 space flamewar to slow you down.
  16. How do these combine? Better together Rave Infer Dagger Fills

    in the gaps, helps ensure Android-isms are enforced across libraries. Lint Establishes a baseline set of constraints that you know is satisfied in production. Because RAVE tells you the starting point for data, you know that it will continue to be enforced throughout the lifecycle of the application. Generated objects in DI don’t break the analysis chain. Dagger 1 >> Dagger 2.
  17. • @Inject supported • @Bind even supported • Establishes constraints

    even in the lifecycle of injection. Dagger + Infer
  18. • Remember the infer modes from a few slides ago?

    • Catch missing annotations • Those are now enforced with RAVE when they terminate in parts of your mobile app. Infer + RAVE
  19. Let’s say we find a new way to prevent a

    systematic problem. • Remember String.format? • Custom grade plugins apply this over all our code. • Can apply across many teams. • If it doesn’t get applied widely, it doesn’t matter. Tying it all together Gradle to the rescue
  20. Lots of fragments here, and other Droidcon talks. Hope to

    have more to share soon. View Based Development Easy to understand, lifecycle is complicated, fast testing. Stick with POJOs By paying attention to testing at the start, we make it much easier to separate and isolate code. Testability And more…