Video description
Optimize the decisions that define your code by exploring the common mistakes and intentional tradeoffs made by expert developers.
In Software Mistakes and Tradeoffs you will learn how to:
- Reason about your systems to make intuitive and better design decisions
- Understand consequences and how to balance tradeoffs
- Pick the right library for your problem
- Thoroughly analyze all of your service’s dependencies
- Understand delivery semantics and how they influence distributed architecture
- Design and execute performance tests to detect code hot paths and validate a system’s SLA
- Detect and optimize hot paths in your code to focus optimization efforts on root causes
- Decide on a suitable data model for date/time handling to avoid common (but subtle) mistakes
- Reason about compatibility and versioning to prevent unexpected problems for API clients
- Understand tight/loose coupling and how it influences coordination of work between teams
- Clarify requirements until they are precise, easily implemented, and easily tested
- Optimize your APIs for friendly user experience
Code performance versus simplicity. Delivery speed versus duplication. Flexibility versus maintainability—every decision you make in software engineering involves balancing tradeoffs. In Software Mistakes and Tradeoffs you’ll learn from costly mistakes that Tomasz Lelek and Jon Skeet have encountered over their impressive careers. You’ll explore real-world scenarios where poor understanding of tradeoffs lead to major problems down the road, so you can pre-empt your own mistakes with a more thoughtful approach to decision making.
Learn how code duplication impacts the coupling and evolution speed of your systems, and how simple-sounding requirements can have hidden nuances with respect to date and time information. Discover how to efficiently narrow your optimization scope according to 80/20 Pareto principles, and ensure consistency in your distributed systems. You’ll soon have built up the kind of knowledge base that only comes from years of experience.
About the Technology
Every step in a software project involves making tradeoffs. When you’re balancing speed, security, cost, delivery time, features, and more, reasonable design choices may prove problematic in production. The expert insights and relatable war stories in this book will help you make good choices as you design and build applications.
About the Book
Software Mistakes and Tradeoffs explores real-world scenarios where the wrong tradeoff decisions were made and illuminates what could have been done differently. In it, authors Tomasz Lelek and Jon Skeet share wisdom based on decades of software engineering experience, including some delightfully instructive mistakes. You’ll appreciate the specific tips and practical techniques that accompany each example, along with evergreen patterns that will change the way you approach your next projects.
What’s Inside
- How to reason about your software systematically
- How to pick tools, libraries, and frameworks
- How tight and loose coupling affect team coordination
- Requirements that are precise, easy to implement, and easy to test
About the Reader
For mid- and senior-level developers and architects who make decisions about software design and implementation.
About the Authors
Tomasz Lelek works daily with a wide range of production services, architectures, and JVM languages. A Google engineer and author of C# in Depth, Jon Skeet is famous for his many practical contributions to Stack Overflow.
Quotes
Great book that I wish I had earlier in my career. Many hard-learned lessons contained in these pages.
- Dave Corun, Avanade
Clear and to-the-point summation of years of real-life experience in software engineering. A must-read for all newcomers to the software engineering world.
- Rafael Avila Martinez, Mastercard
Shines a light on the intrinsic conflicts of the programming process and how they impact the code you write.
- Roberto Casadei, Università di Bologna
Summarizes the main pain points for every software developer and presents solutions in a clear and didactic way.
- Nelson González, General Electric
Table of Contents
Chapter 1. Introduction
Chapter 1. Code design patterns and why they do not always work
Chapter 1. Architecture design patterns and why they do not always work
Chapter 2. Code duplication is not always bad: Code duplication vs. flexibility
Chapter 2. Libraries and sharing code between codebases
Chapter 2. Code extraction to a separate microservice
Chapter 2. Looking at the tradeoffs and disadvantages of a separate service
Chapter 2. Improving loose coupling by code duplication
Chapter 2. Looking at inheritance and tight coupling
Chapter 3. Exceptions vs. other patterns of handling errors in your code
Chapter 3. Best patterns to handle exceptions in the code that you own
Chapter 3. Anti-patterns in exception handling
Chapter 3. Exceptions from third-party libraries
Chapter 3. Exceptions in multithread environments
Chapter 3. Functional approach to handling errors with Try
Chapter 3. Using Try in production code
Chapter 3. Performance comparison of exception-handling code
Chapter 4. Balancing flexibility and complexity
Chapter 4. Allowing clients to provide their own metrics framework
Chapter 4. Guarding against unpredictable usage of the hooks API
Chapter 4. Providing extensibility of your APIs via listeners
Chapter 4. Flexibility analysis of an API vs. the cost of maintenance
Chapter 5. Premature optimization vs. optimizing the hot path: Decisions that impact code performance
Chapter 5. Optimizing processing based on false assumptions
Chapter 5. Hot paths in your code
Chapter 5. A word service with a potential hot path
Chapter 5. Hot path detection in your code
Chapter 5. Improvements for hot path performance
Chapter 5. Optimizing word exists using a cache
Chapter 6. Simplicity vs. cost of maintenance for your API
Chapter 6. Directly exposing settings of a dependent library
Chapter 6. Adding new setting for the cloud client library
Chapter 6. Deprecating/removing a setting in the cloud client library
Chapter 7. Working effectively with date and time data
Chapter 7. Machine time: Instants, epochs, and durations
Chapter 7. Civil time: Calendar systems, dates, times, and periods Part 1
Chapter 7. Civil time: Calendar systems, dates, times, and periods Part 2
Chapter 7. Time zones, UTC, and offsets from UTC Part 1
Chapter 7. Time zones, UTC, and offsets from UTC Part 2
Chapter 7. Date and time concepts that hurt my head
Chapter 7. Preparing to work with date and time information
Chapter 7. Clarifying date and time requirements Part 1
Chapter 7. Clarifying date and time requirements Part 2
Chapter 7. Using the right libraries or packages
Chapter 7. Improving testability by avoiding defaults Part 1
Chapter 7. Improving testability by avoiding defaults Part 2
Chapter 7. Representing date and time values in text Part 1
Chapter 7. Representing date and time values in text Part 2
Chapter 7. Explaining code with comments
Chapter 7. Handling ambiguous or skipped times
Chapter 8. Working with evolving time zone data
Chapter 8. Leveraging data locality and memory of your machines
Chapter 8. Data partitioning and splitting data
Chapter 8. Partitioning vs. sharding
Chapter 8. Join big data sets from multiple partitions
Chapter 8. Data processing: Memory vs. disk
Chapter 8. Calculating access times
Chapter 8. Implement joins using Apache Spark
Chapter 9. Third-party libraries: Libraries you use become your code
Chapter 9. Concurrency models and scalability
Chapter 9. Testability
Chapter 9. Testing with fakes (test double) and mocks
Chapter 9. Dependencies of third-party libraries
Chapter 9. Choosing and maintaining third-party dependencies
Chapter 9. Security and updates
Chapter 10. Consistency and atomicity in distributed systems
Chapter 10. Producing data and idempotency
Chapter 10. A naive implementation of a deduplication library
Chapter 10. Common mistakes when implementing deduplication in distributed systems
Chapter 10. Making your logic atomic to prevent race conditions
Chapter 11. Delivery semantics in distributed systems
Chapter 11. Producer and consumer applications based on Apache Kafka
Chapter 11. The producer logic
Chapter 11. Consumer code and different delivery semantics
Chapter 11. Restarting from the earliest or latest offsets
Chapter 11. Leveraging delivery guarantees to provide fault tolerance
Chapter 12. Managing versioning and compatibility
Chapter 12. Semantic versioning
Chapter 12. Versioning for libraries
Chapter 12. Source, binary, and semantic compatibility Part 1
Chapter 12. Source, binary, and semantic compatibility Part 2
Chapter 12. Techniques for handling breaking changes
Chapter 12. Managing internal-only libraries
Chapter 12. Common versioning strategies Part 1
Chapter 12. Common versioning strategies Part 2
Chapter 12. Further versioning considerations
Chapter 12. Versioning for data storage
Chapter 12. Migrating data within a storage system
Chapter 12. Expecting the unexpected
Chapter 12. Separating API and storage representations
Chapter 13. Keeping up to date with trends vs. cost of maintenance of your code
Chapter 13. Do-it-yourself (DIY) dependency injection
Chapter 13. When to use reactive programming
Chapter 13. Using CompletableFuture
Chapter 13. When to use functional programming
Chapter 13. Using lazy vs. eager evaluation