Software Mistakes & Tradeoffs • Tomasz Lelek & Mark Rendle

Learn essential software engineering principles including API design, dependency management, distributed systems, and making thoughtful technical tradeoffs for long-term success.

Key takeaways
  • Writing software that remains relevant for years requires careful consideration of compatibility, versioning, and avoiding chasing every new trend

  • Taking dependencies on third-party libraries means becoming responsible for supporting those dependencies long-term - evaluate trade-offs carefully

  • When building distributed systems, consider factors like:

    • Network partitions and failures
    • Idempotency of APIs
    • Backwards/forwards compatibility
    • Data format evolution
    • Correlating logs and traces
  • Code duplication is not always bad - sometimes simpler than complex abstractions trying to unify slightly different use cases

  • GraphQL and gRPC offer different trade-offs for service communication:

    • GraphQL allows selective field fetching
    • gRPC provides strict contracts via protobuf
    • Consider wire format compatibility needs
  • Multi-tenancy brings complexity but can reduce costs - isolate customers and consider data separation

  • Don’t blindly adopt microservices - evaluate if the added complexity is warranted for your use case

  • When designing APIs:

    • Plan for evolution and versioning
    • Consider backwards compatibility
    • Add extension points thoughtfully
    • Make operations idempotent
  • Logging and telemetry require careful design in distributed systems:

    • Correlation between services
    • Sampling strategies
    • Storage duration needs
    • Cost implications
  • Framework choices should be based on proven production usage rather than hype - new isn’t always better