Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Orthogonality: A Strategy for Reusable Code


Published on

Published in: Software
  • Be the first to comment

Orthogonality: A Strategy for Reusable Code

  1. 1. ORTHOGONALITY A strategy for reusable code @rsebbe
  2. 2. Orthogonality • Why this talk? • I saw some frameworks with unmanageable complexity. “We do complex stuff, so complexity is OK” • Most of the time, it’s not! • Hoping to share some techniques that will help.
  3. 3. Orthogonality • What is it? • Make <features> that don’t(*) depend on each other. • (*) minimally depend • Where <feature> is: • Code - Method - Class - Library - Project - App - etc. • Self-discipline
  4. 4. Orthogonality • Why? • Easier maintenance. Changes to some part of the code shouldn’t affect some other part. • Easier reading. Because less (told or untold) dependencies. • Easier reuse. • Future-proof, adapts more easily.
  5. 5. Orthogonality • How? • Some prefer to “think before”. Does not really work for me. (could work for you) • I start from real-world needs & use-cases, not trying to predict them *all* beforehand. • Then I continuously challenge the design, and try to improve it with new real-world usage, until it settles/converges.
  6. 6. Levels App Library Class Method Code
  7. 7. App Library Class Method • One purpose (avoid Swiss knives) • Expose what’s strictly required • Less state (fewer properties) & immutability • One purpose • Clear naming • Option dictionaries instead of signature variants • One purpose, keep them thematic • Don’t expose internals • Limit external dependencies (vertical slicing) • One purpose • Factor them out, make reusable libs (horizontal slicing) Code • One purpose code blocks, think of those as a “flow”, avoid local hacks • Use local variables Orthogonality
  8. 8. Techniques • Think Lego® Bricks (standard, reusable blocks), avoid custom solutions. • Keep as much internal things as possible. (Swift) • Make abstractions, handle complexity internally (~ class clusters) • Take a step back when designing APIs • Use of static libs / frameworks / resource bundles • Use categories • Minimize state, favor the immutable.
  9. 9. API • A meeting point. • Insulates inside from outside. • Keep complexity inside, there’s really no point in exposing it. • An API separates a feature from its implementation choices.
  10. 10. Anatomy of a Method • Method signature, required args, optional ones, return values, completion handlers. • Be aware of the flow & dependencies • No internal returns. Single entry, single exit.
  11. 11. Global Variables • Constants that absolutely need to be known outside: OK • Avoid otherwise, they break orthogonality
  12. 12. Local variables… … insulate your code from the outside (think threads) • Interactions with self have a meaning. Don’t abuse those. Consider them as input / output for your code. • Code with lots of reference to self or ivar is suspect.
  13. 13. Less State • Each property has to be maintained over the lifetime of the object. • It’s like planting a tree. It’s cool & nice, until you’re mowing the lawn around it. • Very often, it’s easy and convenient to use a property. But you’ll pay for it over time. • Avoid properties if you can. Even private / internal ones. Compute values from other state or from inputs instead. [Exception: caching]
  14. 14. Immutability • Has been there from day one in Cocoa. • Once you get an object, it won’t change behind your back. It stops all form of change propagation. • Very interesting in a parallel world (GCD). • Makes code robust. • Trendy: Swift’s let & struct vs. class, reactive/ functional programming, etc.
  15. 15. Property Check List • Do you need a property? Why? • Internal or public? • Read-only or read-write? • Public read-only & internal read-write? • Read-only & mutable or read-write & immutable? • Public & read-only or full read-write? read-only + set through specific method?
  16. 16. Method Check List • Private or public? Internal? • Inputs as arguments or options dictionary? • Flow: do you really need those internal return’s? • Are you insulating against self ? • Isn’t it too long, woud factoring it out make more sense?
  17. 17. Class/API Check List • Do you need that class? • Internal or public? Class cluster? • Do you need each of those methods, public/ private? • Do you need to include that additional framework in the .h? Isn’t a .m inclusion enough? • Do you compartmentalize deps with categories?
  18. 18. Fruit Ninja Large App Framework Framework Framework Framework App Framework Horizontal Slicing
  19. 19. Large Framework, w/ all kinds of dependencies Vertical Slicing Framework Ext A Ext B
  20. 20. Keep cool, man! • Good framework, method, API design is clear for everyone. There’s not that much room for ego or personal preferences. • Junior could come up with a better design. That’s OK, you should welcome it & even encourage it! Be thankful for learning new stuff. • Search for design examples. It helps. For API design, Apple *typically* makes effort about this. (OK, they screw up sometimes) • When you reach good design, you typically feel you’ve achieved something. It fits nicely together, hacks are not needed, it is easily reusable… But don’t stop there! • Simplicity of code often converges to the same design, even from people with different backgrounds.
  21. 21. Case Studies
  22. 22. CeedBase CeedVision CeedGL CeedMath CeedAnalytics CeedShare CeedImage CeedCamera CeedDiagnosis CeedOCR CeedTranslate CeedJPEG CeedPageDetection CeedUI CeedSSL CeedReceipt
  23. 23. Case Study 1: CeedOCR • Reusable OCR library • Possibly different OCR engines • Mac / iOS DEMO: Prizmo
  24. 24. Case Study 1: CeedOCR • Simple API: 1 class, 1 method. OCR engines are strings. • Similar to class-cluster design (variety of internal classes) • No internal API is exposed (engine types, classes, etc.) • Dynamically looked up (not linked -> Class is Nil) • Extensible through delegation (binarization)
  25. 25. Case Study 2: CeedAnalytics • Reusable Analytics library. Goal: track which app features are used, which are not. • Possibly different backends (Google, Countly…) • Similar solution as CeedOCR DEMO: Prizmo
  26. 26. Case Study 3: CeedVision • Has a class to perform Accelerate-based image processing • Variety of image source options (CoreVideo, CoreImage, OpenCV, CoreGraphics, vImage…) DEMO: Prizmo
  27. 27. Case Study 3: CeedVision • Core features part of the class • Input options as categories (Swift: extensions)
  28. 28. Case Study 4: CeedImage • GPU Image Processing lib, similar to Core Image (tiled rendering) but with more control (color vs. gray, memory cache…). • Optional features (external JPEG lib) • We don’t want app have JPEG part if app don’t need it (external lib dep, maintenance…) DEMO: Hydra
  29. 29. Fruit Ninja CeedImage CeedImage Framework Vertical Slicing +JPEG
  30. 30. Case Study 4: CeedImage • Use extension/category for the optional feature (JPEG) • Put it in its own library: CeedImage.JPEGExt.a • App link against that lib if it needs the feature.
  31. 31. Case Study 5: CeedGL • Obj-C Wrapper for OpenGL • Optional features: handling of Core Video buffers • We don’t want app have Core Video dependency if they don’t need it • We use a separate library: CeedGL.CoreVideoExt.a • It’s open source -> have a look! DEMO: Hydra
  32. 32. Tips & Tricks
  33. 33. Misc. • Cocoapods
  34. 34. Frameworks or static libs? • Frameworks are available on iOS 8+ (any OS X) • We use frameworks to share code between app and extensions, static libs otherwise. • Libraries can have their resource bundle • Frameworks can be built from libraries
  35. 35. Frameworks or static libs? Libs.a PrizmoKit (Framework) Prizmo PrizmoKit (Framework) Cleanup Extension PrizmoKit (Framework) Lib A.a Lib B.a Lib C.a
  36. 36. Tips & Tricks • OK, but libs that depend on libs are a mess in Xcode. • How do you solve that? Use scheme to force lib build order? No, cumbersome. • There’s a better way.
  37. 37. Workspace Project A Lib A Project B Lib B (depends on Lib A) Project C App (depends on Lib A, Lib B) Tips & Tricks
  38. 38. Workspace Project A Lib A Project B Lib B (depends on Lib A) Project C App (depends on Lib A, Lib B) Tips & Tricks
  39. 39. Workspace Project A Lib A Project B Lib B (depends on Lib A) Project C App (depends on Lib A, Lib B) Stub A • Using (empty) stub libraries, clean schemes! implicit dependency explicit dependency
  40. 40. THANK YOU