Acknowledgments
Introduction
1The Problems with Component-based Rails and Why Today’s Tooling Is More Powerful
- 1.1The inescapable challenges with components
- 1.2Component-based Challenges
- 1.2.1External dependency drift
- A story of dependency drift: “Oops! We just lost two orders of magnitude”
- 1.2.2Configuration drift
- A story of configuration drift: Rails initializers doing what?
- 1.2.3Global impact of local changes
2Getting started with packaging in a Rails application
- Delete the app folder?
- 2.1Let’s get started
- Comparing to CBRA
- 2.2From one to many packages
- 2.2.1Packwerk packages vs gems as components
- Example package structure
- 2.2.2A completely “packagified” application
- 2.2.3Introducing app/packages
- 2.2.4Getting things to work
- 2.2.5Making Packwerk packages
- Not all violations are created equal: ActiveRecord oh my
- 2.2.6Visualizing dependencies
- Comparing to CBRA
- 2.3Accepting the intended dependencies - explicitly adding package dependencies
- 2.4Removing the circular dependencies - creating rails_shims package
- 2.5Analyzing and removing root dependencies (almost) - Aligning app and test code
- Alternative structures
- 2.6Removing all dependencies from the root package
- 2.7Simplifying package loading
- 2.8Recapping differences and similarities to components
3Making Components Work with Packages
- 3.1Engines
- 3.2Gems
- 3.2.1Converting the gem fully into an engine
- 3.2.2Converting the gem into an engine (as little as possible!)
4Beyond Dependencies: Making More Modularization Gradual
- 4.1Gradual Modularization as A New Model for Application Composition
- 4.2Gradual Typing as a Role Model
- 4.3Commonalities of previous modularization approaches
- 4.4Gradularity - Modularization Game Changer
- 4.5Motivating More Modularity
- 4.6Privacy
- 4.7Architectural layers
- 4.8Visibility
- 4.9Folder visibility
- 4.10API Documentation
- 4.11API Typing
- 4.12Package Namespace
- 4.13API Structure
- 4.14Missing pieces
5Dependency Violation Management Refactorings
- 5.1Do absolutely nothing
- 5.2Accept the dependency
- 5.3Merge the two packages
- 5.4Split the violated package
- 5.5Move the code between packages
- 5.6Duplicate the functionality
- 5.7Abstract away the dependency
- 5.8Dependency injection
- 5.8.1Naive dependency injection
- 5.8.2Dependency injection with typing
- 5.8.3Dependency injection with typing and type abstraction
- 5.9Dependency Location - The service locator pattern
- 5.10Emit and listen to events
- 5.10.1To event or not to event - and where?
- 5.10.2Calculating backend responses with events
- 5.10.3Determining where to send responses
- 5.10.4Wiring backend and frontend together
- 5.10.5The package effect of eventing
- 5.11Beyond dependency refactorings
6Privacy Violation Management Refactorings
- 6.1Packages without consumers should protect their public API
- 6.1.1The root package
- 6.1.2The UI and admin packages
- 6.1.3
packages/prediction_interfaceand interface classes - 6.2Expose existing service classes
- 6.3Expose existing service classes
- 6.4ActiveRecord handled naively
- 6.5Hide ActiveRecord
- 6.5.1A new form of
Team - 6.5.2A
TeamRepositoryto manage teams - 6.5.3Migrating consumers to the new API
- 6.6Where are technical refactorings and to which end
7RubyAtScale
- 7.1The giants whose shoulders we stand on
- 7.2Packwerk Visual Studio Code Plugin
- 7.3Danger! Packwerk
- 7.4Code Teams
- 7.5ParsePackwerk and Packs::Specification
- 7.6Code Ownership
- 7.7Packs
- 7.8Package Statistics
- 7.9Honorable mentions: More of Gusto’s RubyAtScale
8Measuring Modularization Progress
- 8.1Basic technical measures of modularization progress
- 8.1.1How modularized is the app?
- 8.1.2Are there an adequate amount of packages?
- 8.1.3How much are packages owned by only one team?
- 8.1.4How discerning is the package dependency graph?
- 8.1.5Basic technical measures create a path for improvement
- 8.2Refining technical measures of modularization progress
- 8.2.1How many packages use a given structure enforcement?
- How many packages protect themselves from being used unintentionally?
- 8.2.2Usage metrics for package-quality metrics
- 8.3How to use technical modularization metrics
- 8.4Sociotechnical measures that go beyond modularization
- 8.4.1High-level vs low-level metrics (and tests)
- 8.4.2The DevOps Research and Assessment (DORA) metrics
- 8.4.3The SPACE framework for Developer Productivity
9How to Create Modularization Progress
- 9.1To start on a modularization journey
- Managing a multitude of options
- 9.2Skills - Getting started
- 9.3Vision - Apps and libraries
- 9.3.1Applications and Libraries - aspirationally!?
- 9.3.2Monoliths and package types
- 9.3.3What makes a package extractable
- 9.3.4Extractable library
- 9.3.5Extractable applications
- 9.3.6How far to go
- 9.3.7The vision behind the vision
- 9.4Action Plan
- 9.4.1Strider Bikes
- 9.4.2Strider bikes - what now?
- 9.4.3Fragments of an action plan
- 9.5Resources
- 9.6Incentives
10Polyglot Persistence, Polyglot Approaches
- 10.1Domain-appropriate implementation choices
- 10.2Domain-specific requirements balanced with application standardization
- 10.3Using Eventide to create a backend component
- 10.3.1An autonomous, event-sourced component for predictions
- 10.4Using Hanami inside Rails
- 10.4.1I’ll take a slice!
- 10.4.2A slice is a package
- 10.5Conclusion
11Archive. Gradual Modularization: A New Model for Application Composition
- 11.0.1Enforce Visibility
- 11.0.2Allow privacy circumvention
- External and internal tests in Go
- 11.0.3API versioning
- 11.0.4Enforcing a package namespace
- 11.0.5Enforcing a separate database
- 11.0.6Enforcing a typed API
- 11.0.7Enforcing proper documentation
- 11.0.8Configurable failure modes
- 11.0.9Here is my code, run it in the cloud for me, I do not care how
- 11.0.10Analyze to modularize the right stuff
- 11.0.11Caveats
- 11.0.12Managing the caveats