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

Chicago Roboto: Everything is an API

Chicago Roboto: Everything is an API

When creating a new app module, or modularising an existing one, it becomes easy to forget who might be consuming it. It becomes easy to forget that every decision you make will affect how it is used, or in the worst case, abused. We’re told that code should document itself, but how do these design decisions reflect in the understanding of intended use?

Just because we might not be exposing a module as a public or open-sourced library, doesn’t mean we can’t benefit from making good decisions towards an effective and sensible API. By taking the stance that every piece of code we write is an API we can build more versatile and scalable applications.

In this talk, I’ll discuss how you can apply best practices from the open-source world to your project, to guard implementations, provide concise and specific contracts, practical documentation mechanisms, and how doing so can aid (or harm) your build time.

Ash Davies

August 01, 2022
Tweet

More Decks by Ash Davies

Other Decks in Programming

Transcript

  1. Ash Davies
    Android & Kotlin GDE Berlin
    @askashdavies
    Everything is an API
    Chicago Roboto - Aug 22’ 󰑔

    View full-size slide

  2. What is an API?
    Article Periodocal Incollection…?
    Accountable Property Inventory...?
    Acquisition Program Integration…?
    Academic Performance Index…?
    Asset Priority Index....?
    Annual Parasite Incidence…?

    View full-size slide

  3. Application Programming Interface
    noun
    A set of functions and procedures allowing the creation of applications
    that access the features or data of an operating system, application, or
    other service.

    View full-size slide

  4. Communication



    View full-size slide

  5. Language 🗣
    󰎼 ¿Qué
    tal?
    󰧻 Helô
    󰏃 Salut!
    󰐮 Privet
    󰏅 Hello!
    󰏢 Ciao
    󰎩 Nǐ
    hǎo
    󰎲 Hallo
    󰐨 Oi
    󰎺 Ahlan
    󰏮Anyoung
    󰐴 Hej
    󰏏 Yassou
    󰑍 Selam

    View full-size slide

  6. Application Programming
    Interface
    Representational State Transfer
    Simple Object Access Protocol
    Remote Procedure Call
    Transactional Agreement Protocol
    Atomic Resource Translation
    Application Programming
    Interface

    View full-size slide

  7. APIs
    curl \
    -H "Accept: application/vnd.github.v3+json" \
    https://api.github.com/repos/octocat/hello-world/actions/artifacts
    What does an API look like?

    View full-size slide

  8. APIs
    {
    "total_count": 2,
    "artifacts": [
    {
    "id": 11,
    "node_id": "MDg6QXJ0aWZhY3QxMQ==",
    "name": "Rails",
    "size_in_bytes": 556,
    "url": "https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/11",
    "archive_download_url": "https://api.github.com/repos/octo-org/octo-docs/actions/artifacts/11/zip",
    "updated_at": "2020-02-21T14:59:22Z"
    }
    ]
    What does an API look like?

    View full-size slide

  9. ● SOAP (XML)
    ● RESTful (JSON)
    ● GraphQL
    ● gRPC (Proto)
    APIs Protocols
    Just a small slice...
    monkeyuser.com

    View full-size slide

  10. Hierarchy
    APIs

    View full-size slide

  11. Android API Council
    android.googlesource.com
    /platform/developers/docs
    /+/refs/heads/master
    /api-guidelines/index.md QR Codes? In 2021? Srsly?

    View full-size slide

  12. Software Development Kit
    noun
    A set of tools for third-party developers to use in producing
    applications using a particular framework or platform.
    "the documentation and SDKs have already been updated to reflect the
    new capabilities"

    View full-size slide

  13. ¯\_(ツ)_/¯

    View full-size slide

  14. ● Increased learning curve
    ● Longer to peer review
    ● Unpleasant to resolve
    ● Increased risk of bugs
    ● Slowed feature delivery
    API Decisions
    Cost of Technical Debt

    View full-size slide

  15. “Debugging is like being the detective in
    a crime movie where you are also the
    murderer”
    - Filipe Fortes

    View full-size slide

  16. ● Your code will always be consumed by other people
    ● Technical debt is not often resolved or paid back
    ● Have respect for your colleagues, make their lives easier
    ● Test code should also be considered production ready
    API Decisions
    Double standards

    View full-size slide

  17. “Always code as if the guy [sic] who ends
    up maintaining your code will be a
    violent psychopath who knows where you
    live”
    - John Woods

    View full-size slide

  18. Good Code? 🏆

    View full-size slide

  19. ● No such thing as perfect code
    ● Perfect is the enemy of good
    ● Perfect solution fallacy (Nirvana fallacy)
    ● Problem for API maintainers
    ● Done is ok, work on making it better
    Good Code?! 😭
    Not so easy...

    View full-size slide

  20. “Dans ses écrits, un sage Italien, dit
    que le mieux est l'ennemi du bien”
    - Voltaire (François-Marie Arouet)

    View full-size slide

  21. ● Keep your API surface as small as possible
    ● Allow yourself room for change
    ● Try not to expose behaviour
    Code Progressively
    Through abstraction...

    View full-size slide

  22. ● Prefer interface contracts
    ● Composition over inheritance
    ● Interface segregation principle
    ● Single responsibility principle
    Hiding Implementations...
    Through abstraction...

    View full-size slide

  23. ● Javadoc can sometimes be useful if maintained
    ● Code should always be self-documenting
    ● Name considerably and with purpose
    ● Consider sources of code smell
    Usefulness of Documentation
    “What’s a Javadoc?!”

    View full-size slide

  24. ● Conditional statements
    ● Iteration or recursion
    ● Polymorphism
    ● Mutability
    ● Significant indentation
    Code Smell 👃
    “My God! What is that smell?” - Veronica Corningstone

    View full-size slide

  25. “There are only two hard things in
    Computer Science: cache invalidation and
    naming things”
    - Phil Karlton

    View full-size slide

  26. Meaningful Names
    Naming is hard.

    View full-size slide

  27. Meaningful Naming
    for (i: Int in kS) {
    try {
    c.connect(i)
    } catch (e: Throwable) {
    // Meh 󰤇
    }
    }
    Unclear purpose or intention

    View full-size slide

  28. Meaningful Naming
    for (index: Int in keySet) {
    try {
    client.connect(index)
    } catch (ignored: Throwable) {
    }
    }
    Unclear purpose or intention

    View full-size slide

  29. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures

    View full-size slide

  30. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures
    Method is visible only to members in the same package

    View full-size slide

  31. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures
    Method will return a result asynchronously, can only be accessed by coroutine or by another
    suspended method

    View full-size slide

  32. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures
    Method can be used with the Kotlin infix notation
    Eg. val result: Boolean = “12345” contains “234”

    View full-size slide

  33. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures
    Receiver indicates the scope of the function, must be called as an extension on this type

    View full-size slide

  34. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures

    View full-size slide

  35. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures
    Named parameters with type give us information about how to call the method

    View full-size slide

  36. Meaningful Naming
    internal suspend infix fun String.contains(value: String): Boolean
    Signatures
    Method return type tells us how to use the result

    View full-size slide

  37. Meaningful Naming
    fun updateClaimWithPolicyDetails(c: Claim, pc: PolicyCriteria, identifier: String)
    fun getIfNotSetWithDefault(value: Any): String
    fun compareAndSet(value: Any): Boolean
    fun isNullOrEmpty(value: String): Boolean
    Signatures

    View full-size slide

  38. Meaningful Naming
    public interface ViewStateFactory { /* ... */ }
    internal class ViewStateFactoryImpl { /* ... */ }
    Interfaces

    View full-size slide

  39. Impure Functions
    var values: MutableMap = mutableMapOf('a' to 1)
    fun modify(items: MutableMap): Int {
    val b: Int = 1;
    items['a'] = items['a'] * b + 2;
    return items['a'];
    }
    val c = modify(values);

    View full-size slide

  40. Interface Composition
    Prefer interface composition over inheritance
    ● Inheritance forces the consumer to use a base class
    ● Limitations on extending abstract classes
    ● Potentially exposes protected behaviour
    ● Prohibits Kotlin interface delegation

    View full-size slide

  41. Interface Abstraction
    public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
    }
    internal class ContextScope(context: CoroutineContext) : CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    }
    public fun CoroutineScope(context: CoroutineContext): CoroutineScope {
    return ContextScope(if (context[Job] != null) context else context + Job())
    }
    Obfuscate behaviour through interface abstraction

    View full-size slide

  42. Impact analysis, risk containment
    Peer review scrutiny
    Mob programming
    Android API council
    Guild meetings
    Democratise your API Decisions
    But not too much!

    View full-size slide

  43. The elephant in the room...

    View full-size slide

  44. Modularisation
    “Modularise all the things!”

    View full-size slide

  45. Modularisation
    Concurrency

    View full-size slide

  46. Modularisation
    Build Cache / Scan
    gradle.com

    View full-size slide

  47. Modularisation
    Pitfalls
    ● Misaligned product flavours
    ● Misbehaving dependencies
    ● Incorrect configurations

    View full-size slide

  48. ● Always a potential for risk
    ● Make use of annotations!
    ○ @Deprecated(message: String, replaceWith: ReplaceWith, level: DeprecationLevel)
    ○ @RequiresOptIn(message: String, level: Level)
    ○ @TechnicalDebt(issue: String, message: String)
    ○ @VisibleForModularisation(otherwise: ProductionVisibility)
    But,
    we’re all human… 󰤇

    View full-size slide

  49. @Deprecated(
    message = "CoroutineScope.rxCompletable is deprecated in favour of top-level rxCompletable",
    level = DeprecationLevel.ERROR,
    replaceWith = ReplaceWith("rxCompletable(context, block)")
    )
    public fun CoroutineScope.rxCompletable(
    context: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> Unit
    ): Completable = rxCompletableInternal(this, context, block)
    We’re all Human 󰤇
    Migration Tools

    View full-size slide

  50. Half screen photo slide if
    text is necessary
    We’re all Human 󰤇
    Decision Paralysis
    The worst decision is a decision
    not made in time.

    View full-size slide

  51. ● Code that documents itself?
    ● Code that can be changed easily?
    ● Easily and readily maintainable?
    ● Follows all the design principles?
    Conclusion
    Good code is...

    View full-size slide

  52. ● Code that documents itself?
    ● Code that can be changed easily?
    ● Easily and readily maintainable?
    ● Follows all the design principles?
    ● Code that can be easily deleted.
    Conclusion
    Good code is...

    View full-size slide

  53. “Every existing thing is born without
    reason, prolongs itself out of weakness
    and dies by chance.”
    - Jean-Paul Sartre

    View full-size slide

  54. “Every line of code is written without
    reason, maintained out of weakness, and
    deleted by chance”
    - Jean-Paul Sartre

    View full-size slide

  55. Explicit mode for library authors (Kotlin)
    TwoHardThing (Martin Fowler)
    The Annotated Programmer (Chet Haase)
    Developers: Your Poorly Named Variables Are Hurting Your Team (Bennett Garner)
    How modularization can speed up your Android app's built tim (Nikita Kozlov)
    Stefan Tilkov on Twitter: "Many enterprise IT departments have become big fans of an “API-first“ strategy"
    The Human Cost of Tech Deb (Erik Dietrich)
    Everything is an API
    Further Reading

    View full-size slide

  56. Ash Davies
    Android & Kotlin GDE Berlin
    @askashdavies
    Thanks!

    View full-size slide