String Transformer
Level: Advanced 60–90 minConcepts: AlgorithmsDesign PatternsEdge CasesRefactoring
Solutions: C# | TypeScript | Python
Build a string transformer that supports chainable operations. Each operation transforms the input string and passes the result to the next operation.
Requirements
- Create a
StringTransformerthat takes an initial string - Support the following operations, all chainable:
capitalise()— capitalise the first letter of each wordreverse()— reverse the entire stringremoveWhitespace()— remove all whitespacesnakeCase()— convert to snake_casecamelCase()— convert to camelCasetruncate(n)— truncate to n characters, adding ”…” if truncatedrepeat(n)— repeat the string n times with a space separatorreplace(target, replacement)— replace all occurrences
result()returns the final transformed string- Operations are applied in order
Test Cases
| Input | Operations | Result |
|---|---|---|
| ”hello world” | capitalise() | “Hello World" |
| "hello world” | reverse() | “dlrow olleh" |
| "hello world” | removeWhitespace() | “helloworld" |
| "hello world” | snakeCase() | “hello_world" |
| "Hello World” | camelCase() | “helloWorld" |
| "hello world” | truncate(5) | “hello…" |
| "hello world” | truncate(50) | “hello world" |
| "ha” | repeat(3) | “ha ha ha" |
| "hello world” | capitalise().reverse() | “dlroW olleH" |
| "hello world” | snakeCase().capitalise() | “Hello_World" |
| "" | capitalise() | "" |
| "HELLO WORLD” | camelCase() | “helloWorld" |
| "hello-world test” | snakeCase() | “hello_world_test” |
Bonus
- Add
cipher(n)— apply a Caesar cipher shifting each letter by n positions - Add
slug()— convert to URL-friendly slug (lowercase, hyphens, no special characters) - Add
mask(n)— mask all but the last n characters with asterisks (useful for credit cards, emails) - Make the transformer immutable — each operation returns a new transformer, allowing branching transformations
Reference Walkthrough
Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/string-transformer. This is an F2 (light builder) kata showcasing the Strategy pattern: every transformation (Capitalise, Reverse, SnakeCase, Truncate(n), Replace(target, replacement), …) is a self-contained class implementing a uniform apply(string) -> string; Pipeline runs them in order; a small test-folder PipelineBuilder makes each scenario a one-line fluent chain.
Scope note — eight required transformations only. The reference implements the eight chainable operations from the spec (capitalise, reverse, removeWhitespace, snakeCase, camelCase, truncate, repeat, replace). The four bonus ideas — cipher(n), slug(), mask(n), and immutable-branching pipelines — are out of scope and listed as stretch goals in the repo README.
- C# (.NET 8, xUnit, FluentAssertions 6.12.0) — walkthrough
- TypeScript (Node 20, Vitest 1.6, TS 5 strict) — walkthrough
- Python (3.11, pytest) — walkthrough
This kata ships in Agent Full-Bake mode at middle gear, the F2 (light builder) tier. See the repo’s Gears section for why middle gear is the deliberate choice.
Related reading
- Katas Are Rehearsal, Not Performance
You don't practice TDD on production code. You practice on katas and bring the muscle memory to production. The gap between knowing TDD and doing TDD is reps. - Agents Amplify Whatever Vocabulary They Find
Agents do not bring vocabulary to your codebase. They mirror what's already there. Strong vocabulary gets agent contributions that read like the team. Weak vocabulary gets faster mediocrity. The work you did for craft reasons just became leverage. - The Hidden Output of TDD Was Never Code
The visible artifact of TDD is a passing test suite. The actual artifact, the one that compounded value over the life of the codebase, was the vocabulary the team built while writing it. The dictionary, not the regression net.