Summary of "Application Infrastructure"
Summary of “Application Infrastructure” Video
Main Topic
The video focuses on managing and testing application infrastructure, particularly how to isolate external dependencies (such as command line interfaces, file systems, databases, etc.) from application logic to improve testability and maintainability.
Key Technological Concepts & Product Features
1. Application Infrastructure Defined
- External systems interacting with an application include networks, services, file systems, databases, global state, clocks, random generators, process arguments, standard input/output, and error codes.
- These are essential but often complicate testing and code clarity.
2. Challenge Overview
- Transform a previously built ROT13 algorithm into a command line application.
- Focus on isolating command line infrastructure cleanly to avoid polluting core logic.
3. Managing Infrastructure - Two Approaches
-
Infrastructure Wrappers:
- Create abstraction layers (modules or classes) around external dependencies.
- Use custom APIs tailored to application needs rather than directly mirroring third-party interfaces.
- Benefits include easier testing and flexibility to change underlying infrastructure without affecting application code.
-
Focused Integration Tests:
- Tests that behave like unit tests but interact with real infrastructure (e.g., real file system or service calls).
- Provide confidence that wrappers work correctly with external systems.
- More complex and time-consuming than unit tests but offer peace of mind and reduce reliance on manual or end-to-end testing.
4. Implementation Details (Node.js Example)
- Isolate command line infrastructure in a dedicated folder/module.
- Wrap Node.js
processglobal object (arguments, stdout, stderr, exit codes) with a customcommandLinemodule. - Write focused integration tests by spawning child processes (
child_process.fork) to test actual command line output and argument parsing. - Handle complexities such as capturing stdout/stderr, asynchronous test completion, and converting buffers to strings.
- Refactor test code to isolate common logic into helper functions returning promises for cleaner, more maintainable tests.
5. Testing Infrastructure Challenges
- Testing infrastructure code is often more complicated than writing it.
- Infrastructure tests can be fragile and require complex setup.
- Despite difficulty, automated focused integration tests reduce manual testing overhead and increase reliability.
- Separation of slow integration tests from fast unit tests is recommended when tests grow large.
6. Practical Usage
- After wrapping and testing infrastructure, integrate it into the application by using the wrapper API.
- Manual testing can complement automated tests initially.
- Future sessions will cover testing with test doubles (mocks) and testing without mocks.
7. Additional Topics Discussed
-
Persistence Testing:
- Using ORM frameworks vs. lightweight SQL libraries.
- Wrapping database queries in infrastructure wrappers.
- Running tests against local or dedicated test databases.
-
Leaky Abstractions:
- Sometimes infrastructure leaks concepts (e.g., transactions).
- Expose necessary abstractions meaningfully to the application layer.
- Example: wrapping database transactions as business-level transactions.
-
Network Calls & Authentication:
- Wrapping retry logic and token refresh inside infrastructure layers.
-
Testing Multi-threaded Applications:
- Use dependency injection to control thread behavior.
- Employ async/await constructs where possible.
- Flaky tests often indicate race conditions or deadlocks.
- TDD helps detect but does not automatically solve concurrency issues.
-
Instrumentation:
- Instrumentation is not built into deliverable code by default.
- Use dependency injection to manage instrumentation and threading code.
Guides / Tutorials Provided
-
Step-by-step live coding of:
- Creating a command line infrastructure wrapper in Node.js.
- Writing focused integration tests using child process forking.
- Handling asynchronous test completion with promises.
- Refactoring test code for clarity and maintainability.
-
Explanation of best practices for isolating infrastructure to improve testing.
- Discussion on balancing complexity and testing effort for infrastructure code.
Upcoming Sessions Announced
- Next Tuesday: Testing with Test Doubles (Mocks).
- Following Tuesday: Testing without Mocks.
- Friday Casual Coding Stream: Extending infrastructure testing with a cribbage example and handling more complex command line cases (error handling, usage messages).
Main Speaker / Source
James Shore — Software development trainer and consultant, host of the Tuesday Lunch and Learn series. Contact: james@jamesshore.com GitHub repo and code referenced: github.com/jamesthore/livestream (tagged with dates for specific sessions).
Summary
This video presents a practical approach to isolating and testing application infrastructure by wrapping external dependencies and writing focused integration tests. It highlights the complexity of infrastructure testing, the benefits of abstraction, and provides a live coding example in Node.js to illustrate these concepts. The speaker also addresses audience questions related to persistence testing, leaky abstractions, network retries, and concurrency testing.
Category
Technology