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

"Type-safe metaprogramming in Swift? Let's talk about sourcery" by Krzysztof Zabłocki

"Type-safe metaprogramming in Swift? Let's talk about sourcery" by Krzysztof Zabłocki

Author's note: Swift has very limited runtime support and no meta-programming features.
Lets take a look at recently released Sourcery and how it can be applied in variety of different use-cases to make development more powerful and enjoyable, while at the same time limiting amount of human mistakes.
This talk was made for CocoaHeads Kyiv #12 which took place July 22 2017.

CocoaHeads Ukraine

July 22, 2017
Tweet

More Decks by CocoaHeads Ukraine

Other Decks in Programming

Transcript

  1. What is metaprogramming? » Metaprogramming means that a program can

    be designed to read, generate, analyse or transform other programs, and even modify itself while running.
  2. What is metaprogramming? » Metaprogramming means that a program can

    be designed to read, generate, analyse or transform other programs, and even modify itself while running. » But in reality the most common use case is to generate boilerplate code automatically
  3. Example of metaprogramming in Ruby from repetitions like this: class

    Developer def coding_frontend p "writing frontend" end def coding_backend p "writing backend" end end
  4. Example of metaprogramming in Ruby with metaprogramming: class Developer ["frontend",

    "backend"].each do |method| define_method "coding_#{method}" do p "writing " + method.to_s end end end
  5. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns:
  6. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality
  7. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing
  8. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing » Data Persistance
  9. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing » Data Persistance » JSON parsing
  10. Why would we want metaprogramming? If we analyze our day

    to day job, we repeat same code patterns: » Equality » Hashing » Data Persistance » JSON parsing » Writing and updating testing Mocks / Stubs
  11. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once
  12. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once » Ease maintenance costs
  13. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once » Ease maintenance costs » Avoid human mistakes
  14. Why would we want metaprogramming? Metaprogramming allows us to: »

    Adhere to DRY principle » Write once, test once » Ease maintenance costs » Avoid human mistakes » Experiment with interesting architecture choices
  15. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all
  16. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it.
  17. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it. » The problem is that when you change it e.g. add new variables
  18. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it. » The problem is that when you change it e.g. add new variables » You might not realize you forgot to update your boilerplate
  19. Avoiding human mistakes I don't have a problem writing boilerplate

    code like Equatable implementation, its simple after all » The problem isn't writing it. » The problem is that when you change it e.g. add new variables » You might not realize you forgot to update your boilerplate » This can cause hard to track bugs
  20. Metaprogramming in Cocoa » Powerful runtime and reflection for Objective-C

    setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options: .new, context: &context)
  21. Metaprogramming in Cocoa » Powerful runtime and reflection for Objective-C

    » Key Value Observing setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options: .new, context: &context)
  22. Metaprogramming in Cocoa » Powerful runtime and reflection for Objective-C

    » Key Value Observing » Key Value Coding setValue(11, forKeyPath: #keyPath(MyClass.variable)) addObserver(self, forKeyPath: #keyPath(MyClass.updatedAt), options: .new, context: &context)
  23. What is available in Swift? Swift reflection » Allows you

    to learn a lot about types at runtime Mirror(reflecting: object)
  24. What is available in Swift? Swift reflection » Allows you

    to learn a lot about types at runtime » Read only Mirror(reflecting: object)
  25. What is available in Swift? Swift reflection » Allows you

    to learn a lot about types at runtime » Read only » Not very useful unless you start interacting with Objective-C runtime or KVC Mirror(reflecting: object)
  26. Already in Swift 4 » New Key Value Paths »

    Deriving Equatable / Hashable
  27. Problems with metaprogramming » Usually untyped, mostly based on strings

    » No compile time errors » Runtime evaluated » Easy to create inconsistent app state » Hard to debug
  28. What is Sourcery? Sourcery scans your source code, applies your

    personal templates and generates Swift code for you, allowing you to use meta-programming techniques to save time and decrease potential mistakes.
  29. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines:
  30. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines: » Stencil
  31. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines: » Stencil » Swift
  32. Templates? Sourcery allows you to write AST aware code, that

    will generate more swift code (or anything you want really). We support three different templating engines: » Stencil » Swift » EJS
  33. Templates? EJS - Effective JavaScript templating. <% for (type of

    types.all) { -%> <%= type.name %> <% } -%>
  34. Sourcery Features » Powered by Apple own SourceKit » Additional

    parsing on top of what SourceKit provides
  35. Sourcery Features » Powered by Apple own SourceKit » Additional

    parsing on top of what SourceKit provides » Generates regular Swift code » No runtime involved » Compiled » Typed
  36. Sourcery Features » Powered by Apple own SourceKit » Additional

    parsing on top of what SourceKit provides » Generates regular Swift code » No runtime involved » Compiled » Typed » Immediate feedback: Create new templates with real-time feedback.
  37. Sourcery Features Source annotations Sourcery supports annotating your classes and

    variables with special annotations, similar to how attributes work in Rust / Java // sourcery: skipPersitance let transientValue: Int // sourcery: jsonKey = "user_name" let name: String
  38. Sourcery Features Inline code generation {% for type in types.all

    %} // sourcery:inline:auto:{{ type.name }}.TemplateName // sourcery:end {% endfor %} // it will add it at the end of your type definition: class MyType { /// code }
  39. How to integrate Sourcery? » Build phase for your project

    » A lot of common templates are distributed with it
  40. How to integrate Sourcery? » Build phase for your project

    » A lot of common templates are distributed with it » When working on new templates use a daemon mode to get real-time feedback.
  41. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts
  42. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses
  43. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks
  44. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks » Diffing
  45. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks » Diffing » LinuxMain
  46. Bundled templates Sourcery is already bundled with basic templates, that

    generate: » Equatable & Hashable » Enum cases & counts » Lenses » Mocks » Diffing » LinuxMain » Decorators
  47. Bundled templates Property level diffing for tests, meaning you can

    go from wall of text like this: To exact difference:
  48. Is it going to slow down my builds? » Fast

    parsing » Caching » Neglible cost in comparsion to Swift build time
  49. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate »

    Write once, test once » Limit human mistakes » Ease maintenance costs
  50. Summary Sourcery available on GitHub: https://github.com/krzysztofzablocki/Sourcery » Eliminate boilerplate »

    Write once, test once » Limit human mistakes » Ease maintenance costs » Create better architecture choices