What's changed: Initial version
1.2Development methodologies and testing
Covers when to use the waterfall, agile, and lean methodologies, the red -> green -> refactor cycle of test-driven development (TDD) that writes tests before implementation, and the role of unit tests, framed as the judgment/diagnosis of "which approach fits this requirement volatility?" and "how do I respond to this failing test?"
Automation code is not write-once; it must follow changing requirements and stay unbroken as it grows. That is exactly why "in what order to develop (methodology)" and "the mechanism that guarantees nothing breaks on change (testing)" are tested. This section covers judging methodology by whether requirements are firm or volatile, and how to run TDD, which writes tests before implementation, as on-the-job judgment: "how do I proceed here?" and "what does this failing test mean?" The goal is not rote methodology names but choosing the right approach for the situation at hand.
1.2.1Choosing a development methodology
- Waterfall is a sequential model that freezes each phase before moving on: requirements -> design -> implementation -> testing -> operations. It suits projects where requirements are clear and stable and where regulation or contracts demand phase evidence. Its downside is that late requirement changes are costly and a working product appears late.
- Agile is an iterative, incremental model that delivers working increments in short iterations (sprints) and adjusts direction from feedback. It is strong where requirements shift or are initially vague. It fits domains like network automation, where environments and demands move.
- Lean emphasizes eliminating waste and validating value fastest. It tests a hypothesis quickly with a minimal build (MVP) and, based on learning, decides whether to continue or pivot. It is compatible with agile, and its core stance is "confirm it is truly needed before building it."
1.2.2Test-driven development (TDD)
- TDD writes tests before implementation. The cycle is red (write a failing test because there is no implementation yet) -> green (write the minimal implementation to pass) -> refactor (tidy the internals while tests stay green). A failing test is an indicator of "unmet specification," not something to delete.
- Unit tests are small checks at the function/method level that run fast and often. In automation scripts, dependencies on devices or APIs are replaced with mocks to verify just the logic reproducibly. Their greatest value is catching regressions (previously working features breaking) early.
Most-tested: waterfall = sequential, firm-requirement projects; agile = short iterations delivering working increments and following change; lean = eliminate waste, fastest validation (MVP); TDD = write tests first, red -> green -> refactor; a failing test indicates the spec and is not deleted. Questions arrive as judgment: "which methodology/approach fits this situation?" and "how do I respond to a failing test?"
Your team is developing a new function summarize_speeds() (aggregating interface speeds pulled from devices) with TDD. You first wrote a failing test expressing the spec "return the sum and max of a speed list" (naturally red, since there is no implementation). A teammate then says, "CI cannot merge while it is red, so let us delete this failing test for now." That mistakes the point of TDD. A red test makes visible "a spec not yet met"; deleting it discards the spec's evidence along with it. The correct next move is to write the minimal implementation to pass and go green—for example, returning sum(speeds) for the total and max(speeds) for the maximum, plainly. Once green, you tidy readability and duplication by refactor, and throughout, the test stays green, guaranteeing you have not broken behavior. In reality you may later find an edge case: summarize_speeds([]) (empty list) makes max([]) throw. The procedure is the same—first add a failing test for the empty-list expected behavior (red) -> implement a branch returning total 0 and max None when empty (green) -> tidy (refactor). On methodology too, a project where the spec emerges as you implement suits agile, which folds in discoveries over short iterations, more than waterfall, which freezes phases up front. The essence is the judgment to read a failing test not as "an annoying red" but as a pointer to the spec to implement next.
| Methodology | How it proceeds | When it fits | Weakness |
|---|---|---|---|
| Waterfall | Sequential, frozen phases | Clear requirements, evidence needed | Weak to late change |
| Agile | Short iterations, working increments | Requirements shift | Harder long-range plan/contract |
| Lean | Cut waste, validate via MVP | Unvalidated new ideas | Too light for large fixed scope |
| TDD | Tests first, red->green->refactor | Logic where regressions matter | Upfront writing cost |
Trap: "Delete the failing test to make CI green" is wrong—a failing test indicates an unmet spec, and what to fix is not the red but the missing implementation; you go green with a minimal implementation. Also wrong: "agile is a speed-first approach that skips tests and design"—agile is a disciplined practice that runs tests/reviews every iteration and coexists with TDD.
1.2.3Section summary
- Waterfall for firm sequential projects, agile for iterating with change, lean for fastest MVP validation—choose by requirement volatility
- TDD writes tests first and runs red -> green -> refactor; a failing test indicates the spec and is turned green with a minimal implementation, not deleted
- Unit tests are fast function-level checks that catch regressions early; handle edge cases in the order "add failing test -> implement -> tidy"
Sign in to track progress — Log in.
Quick check
(just a quick review)Q1. While developing a new feature with TDD, a failing test written before implementation stays red. A member proposes "delete this failing test so CI passes." What is the most appropriate response in this situation?
Q2. In a new network-automation project, the target devices and operational requirements are initially vague and expected to change often as work proceeds. You want to ship working increments early and adjust from feedback. Which methodology fits best?
Q3. A unit test revealed that passing `summarize_speeds([])` (empty list) crashes because the internal `max([])` throws. Following the TDD style, what is the most appropriate next step?

