Skip to content

docs(book): Add capstone chapter — a complete Bookmarks Service#605

Merged
xerial merged 1 commit into
mainfrom
docs/book-capstone
Jun 22, 2026
Merged

docs(book): Add capstone chapter — a complete Bookmarks Service#605
xerial merged 1 commit into
mainfrom
docs/book-capstone

Conversation

@xerial

@xerial xerial commented Jun 22, 2026

Copy link
Copy Markdown
Member

The Book teaches one concept per chapter after Chapter 2. This adds a capstone (Chapter 16, the new Part IX) that threads the core stack into a single working service — the integration view the Rust Book gives with its final project.

What it builds

A small Bookmarks Service, end to end:

  • Data + contractBookmark and a BookmarkService trait, both derives Weaver (ch6)
  • Design wiring shared by production and tests (ch3)
  • RPC over Netty via RPCRouter.of + RPCHandler, with a generated typed client (ch9–10)
  • Retry around the one call that touches the network (ch8)
  • UniTest + Design override to test the real logic without a network (ch4)

Each section links back to the chapter that taught the piece, so it reads as assembly, not new material.

Placement

Lands as Ch 16 / Part IX, after the platform Parts and before the appendices — chosen to avoid renumbering existing chapters. Nav re-threaded (15 → 16 → Appendix A), ToC and sidebar updated. APIs verified against source. pnpm docs:build passes.

🤖 Generated with Claude Code

The book teaches concept-by-concept after Chapter 2; this adds a final
integration chapter that assembles the core stack into one working
service: derives-Weaver data + an RPC trait, a Design-wired in-memory
implementation, an RPC/Netty server, a retry around the one network call,
and a UniTest suite that overrides a single Design binding to test the
real logic without a network.

Lands as Chapter 16 / Part IX (after the platform Parts, before the
appendices) to avoid renumbering. Nav re-threaded (15 -> 16 -> appendices),
ToC and sidebar updated. pnpm docs:build passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the doc Improvements or additions to documentation label Jun 22, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new capstone chapter, 'Part IX — Capstone: 16. A Bookmarks Service,' to the documentation, along with corresponding updates to the navigation links and index. The review feedback highlights two improvement opportunities in the code examples of the new chapter: first, replacing independent atomic variables with a synchronized block in BookmarkServiceImpl to prevent race conditions during compound state transitions; and second, ensuring html.indexOf("</title>") in extractTitle searches from the index of the opening tag to avoid issues with malformed HTML.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +38 to +49
import java.util.concurrent.atomic.AtomicReference

class BookmarkServiceImpl(seed: Seq[Bookmark]) extends BookmarkService:
private val store = AtomicReference(seed.toVector)
private val nextId = java.util.concurrent.atomic.AtomicLong(seed.size + 1L)

def add(url: String, title: String): Bookmark =
val bookmark = Bookmark(nextId.getAndIncrement(), url, title)
store.updateAndGet(_ :+ bookmark)
bookmark

def list(): Seq[Bookmark] = store.get()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using multiple independent atomic variables (AtomicReference and AtomicLong) for compound state transitions (generating a unique ID and appending to the store) can lead to race conditions where the order of elements in the list does not match their IDs. Guarding plain variables with a monitor lock (synchronized) ensures atomicity of the compound transition, guarantees consistent ordering, and reduces memory overhead.

Suggested change
import java.util.concurrent.atomic.AtomicReference
class BookmarkServiceImpl(seed: Seq[Bookmark]) extends BookmarkService:
private val store = AtomicReference(seed.toVector)
private val nextId = java.util.concurrent.atomic.AtomicLong(seed.size + 1L)
def add(url: String, title: String): Bookmark =
val bookmark = Bookmark(nextId.getAndIncrement(), url, title)
store.updateAndGet(_ :+ bookmark)
bookmark
def list(): Seq[Bookmark] = store.get()
class BookmarkServiceImpl(seed: Seq[Bookmark]) extends BookmarkService:
private var store = seed.toVector
private var nextId = seed.size + 1L
def add(url: String, title: String): Bookmark = synchronized {
val bookmark = Bookmark(nextId, url, title)
nextId += 1
store = store :+ bookmark
bookmark
}
def list(): Seq[Bookmark] = synchronized { store }
References
  1. Prefer using plain variables guarded by a monitor lock ('synchronized') instead of multiple independent atomic instances for compound state transitions to ensure atomicity and reduce memory overhead.

Comment on lines +113 to +116
private def extractTitle(html: String): Option[String] =
val open = html.indexOf("<title>")
val close = html.indexOf("</title>")
if open >= 0 && close > open then Some(html.substring(open + 7, close)) else None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In extractTitle, html.indexOf("</title>") searches from the beginning of the HTML string. If there is any occurrence of </title> before the <title> tag (for example, in a comment or malformed markup), close will be less than open, causing the method to return None even if a valid <title>...</title> block exists later. Searching for the closing tag starting from open + 7 resolves this issue.

Suggested change
private def extractTitle(html: String): Option[String] =
val open = html.indexOf("<title>")
val close = html.indexOf("</title>")
if open >= 0 && close > open then Some(html.substring(open + 7, close)) else None
private def extractTitle(html: String): Option[String] =
val open = html.indexOf("<title>")
val close = html.indexOf("</title>", open + 7)
if open >= 0 && close > open then Some(html.substring(open + 7, close)) else None

@xerial xerial merged commit d94efee into main Jun 22, 2026
13 checks passed
@xerial xerial deleted the docs/book-capstone branch June 22, 2026 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant