Serious developers know that code can always be improved. With each iteration, you make optimizations—small and large—that can have a huge impact on your application’s speed, size, resilience, and maintainability.
In Seriously Good Software: Code that Works, Survives, and Wins, author, teacher, and Java expert Marco Faella teaches you techniques for writing better code. You’ll start with a simple application and follow it through seven careful refactorings, each designed to explore another dimension of quality.
about the technology
Great code blends the skill of a programmer with the time-tested techniques and best practices embraced by the entire development community. Although each application has its own context and character, some dimensions of quality are always important. This book concentrates on seven pillars of seriously good software: speed, memory usage, reliability, readability, thread safety, generality, and elegance. The Java-based examples demonstrate techniques that apply to any OO language.
about the book
Seriously Good Software is a handbook for any professional developer serious about improving application quality. It explores fundamental dimensions of code quality by enhancing a simple implementation into a robust, professional-quality application. Questions, exercises, and Java-based examples ensure you’ll get a firm grasp of the concepts as you go. When you finish the last version of the book’s central project, you’ll be able to confidently choose the right optimizations for your code.
AI Reading Assistant
Whole-book reading guide from stratified index samples; jump to passages in the text
Tip the Site
Support this siteYour recognition and a small knowledge-service contribution help keep this technical work open source.Scan the WeChat Pay or Alipay code below. Logged-in and guest visitors can both tip.
WeChat Pay
Alipay
Open WeChat or Alipay and scan. No login required.
AI guide
【One-Line Pitch】
A practical handbook for Java developers who want to move beyond "working" code to code that is fast, memory-efficient, reliable, and elegant—using a single water-container project refactored seven times to explore each quality dimension.
【Book Arc】
- **Opening (~0%–9%)**: Introduces the seven pillars of software quality—speed, memory usage, reliability, readability, thread safety, generality, and elegance—and frames them as competing objectives in a multi-criteria optimization problem. Establishes the internal/external and functional/nonfunctional quality spectrums, plus a quality-interaction table showing trade-offs (e.g., performance hurts readability).
- **Early (~9%–25%)**: Defines the central problem: a water-container system where containers can be connected and share water amounts. Explores three data-storage strategies (per-container fields, shared group objects, representative containers) and walks through a naive reference implementation, exposing bugs like duplicate connections and null-pointer crashes in loops.
- **Early (~25%–34%)**: Dives into Java memory internals—object headers, compressed OOPs, reflection, multithreading monitors, and garbage collection—to explain why even stateless objects cost memory. Introduces big-O notation and time-complexity analysis as the vocabulary for evaluating the refactorings that follow.
- **Middle (~34%–44%)**: First refactoring (Speed1) moves the water amount from each container into a shared Group object, making `addWater` constant-time. A second iteration (Speed2) uses a circular linked list to track group members, but introduces robustness issues when connecting already-connected containers.
- **Middle (~44%–47%)**: Final speed-focused refactoring (Speed3) adopts union-find with path compression and link-by-size policy, achieving near-constant amortized time for all operations. Explains the inverse Ackermann function and why this is theoretically optimal for the problem.
【Key Takeaways】
- **Software quality is a balancing act, not a checklist** (Opening): The seven pillars—speed, memory, reliability, readability, thread safety, generality, elegance—often conflict; e.g., performance hacks hurt readability, and time/space efficiency trade off against each other. This frames all subsequent refactorings as deliberate trade-off decisions, not absolute improvements.
- **Functional vs. nonfunctional qualities map to internal vs. external concerns** (Opening): Functional qualities (what software does) are always external, while nonfunctional qualities (how software is) can be internal (code structure) or external (emergent behavior). This 2D spectrum helps you prioritize which quality to optimize for a given stakeholder.
- **Naive implementations hide subtle correctness bugs** (Early): The reference implementation crashes on null references in loops and corrupts state when connecting already-connected containers—even indirectly. This demonstrates that "working" code is not the same as "correct" code, and robustness must be designed in from the start.
- **Java object memory is dominated by hidden overhead** (Early): Object headers (for reflection, monitors, GC) and compressed OOPs mean even a stateless object costs significant memory; references may be 32-bit but require 8-byte alignment. Understanding this helps you estimate real memory usage, not just field sizes.
- **Moving shared state to a group object enables constant-time updates** (Middle): Speed1 refactoring stores water amount once per connected group instead of per container, making `addWater` O(1) instead of O(n). This is a classic space-for-time trade-off that pays off when groups are large.
- **Union-find with path compression is the theoretical optimum** (Middle): Speed3 achieves near-constant amortized time (O(m·α(n)), where α is the inverse Ackermann function, effectively ≤4 for any practical n) by using tree structures with link-by-size and path compression. This is the gold standard for connectivity problems.
- **Amortized analysis matters more than worst-case for real workloads** (Middle): The book shows that Speed3's amortized performance beats competitors in practice, even though worst-case analysis might suggest otherwise. This teaches you to evaluate algorithms based on realistic operation sequences, not just theoretical bounds.
【Reading Tips】
- **Skim the quality taxonomy in Chapter 1** if you're already familiar with software engineering concepts; the 2D spectrum and interaction table are the key takeaways, not the detailed examples.
- **Deep-read the memory internals section** (object headers, compressed OOPs) if you do performance-sensitive Java work; this knowledge is rarely covered in standard tutorials and directly impacts memory estimation.
- **Focus on the transition from Speed1 to Speed3** as the core of the book; the intermediate Speed2 shows a common pitfall (robustness bugs from naive optimizations) that's worth understanding before moving to the union-find solution.
- **Work through the code listings** rather than just reading the explanations; the bugs in the reference implementation (null loops, duplicate connections) are only fully appreciated by tracing through the logic yourself.
- **Skip the further-reading sections** (Cormen, Fowler, etc.) unless you need deeper background; they're useful pointers but not essential to the main narrative.
【Coverage Limits】
This guide covers the book's opening through the speed-focused refactorings (roughly the first half). The excerpts do not cover the later chapters on memory optimization, reliability, readability, thread safety, generality, or elegance—those refactorings are mentioned in the book's structure but not detailed in the source material.
Page 7
......... 1 1 Software qualities and a problem to solve 3 1.1 Software qualities 4 Internal vs. external qualities 4 Functional vs. nonfunctional qualities 5...
h the following: for (Container c: g) { c.n = n; c.x = z; } This new loop is certainly more readable, but it’s going to crash with a NullPointer Exception as...
isely, the big-O notation establishes an upper bound to the growth of a function. So, O(size1+size2) asserts that our running time grows at most linearly wit...
s of the two groups you’re merging. Then, it checks whether those roots are the same—that is, if the two containers are already connected. Without this step,...
Reference because the groups you merged using the connectTo method are guaranteed to be disjoint in the first place. The implementation for con nectTo shown...
tems, or need to keep a huge amount of data in main memory. As I discussed in chapter 1, space and time efficiency are often at odds. This chapter and the pr...
te Set<Container> group; b Containers connected to this one private double amount; c Amount of water in this container 5.3 Containers that check their contra...
arly. Does the constructor actively check its precondition? 2. Do the same for the parseInt method. 150 CHAPTER 5 Self-conscious code: Reliability through mo...
Support this siteYour recognition and a small knowledge-service contribution help keep this technical work open source.
Scan the WeChat Pay or Alipay code below. Logged-in and guest visitors can both tip.
WeChat PayAlipay
Open WeChat or Alipay and scan. No login required.
Add Tag
Enter tag name (max 50 characters)
Share E-Book
Seriously Good Software - Code that Works, Survives, and Wins (Java). (Marco Faella)(Z-Library)
Scan QR code with your phone to access
Copy the link or scan the QR code to access this e-book on your phone
Share E-Book via Email
Please enter email address
Donation Statistics
¥.00
Total Donations
0
Donation Count
Seriously Good Software - Code that Works, Survives, and Wins (Java). (Marco Faella)(Z-Library)
Find Your Favorite Books
Only registered users can comment after logging in. Comments need to be reviewed by administrators before being displayed
Loading comments...
Reply to Comment
Edit Comment