Software Craft
How do I investigate and improve code?
Reason about the changes.
Build evidence for what your code does. Debug failures, test assumptions, design useful contracts, and improve behavior with measurements.
Work in progress. 2 of 24 lessons are drafted and open to read; they're still being reviewed.
Useful foundations: functions, types, collections, and errors. Runtime lessons support the performance investigations.
Still being written 2 of 24 lessons are drafted and open to read while they're reviewed. Planned topics show where the catalog is going.
Tools and everyday workflow
Start hereSet up the small habits that make every later investigation faster.
Reading documentation and specifications
Where is the real answer? Compare a language specification, standard-library docs, and a blog post, and know which one makes a promise.
TypeScriptGoRustCHaskellJavaREPLs and scratch experiments
How do you test an idea in thirty seconds? Use a REPL or a scratch file to check one behavior before relying on it.
TypeScriptGoRustCHaskellJavaFormatters, linters, and warnings
What can a tool catch before you run anything? Turn on warnings, read lint findings, and let a formatter settle style.
TypeScriptGoRustCHaskellJavaReading unfamiliar code
Where do you start in code you did not write? Find the entry point, follow one path, and write down what you learn.
TypeScriptGoRustCHaskellJavaDebugging with evidence
Build understandingMove from a symptom to a small explanation you can check.
Compiler diagnostics and stack traces
What is the tool telling you, and where did the failure originate? Separate a diagnostic location from the cause.
TypeScriptGoRustCHaskellJavaPrint statements and logging as evidence
What should you print, and where? Turn a print statement into a deliberate observation that can confirm or reject a guess.
TypeScriptGoRustCHaskellJavaBreakpoints, frames, and inspected values
Which values exist at this point? Inspect the call stack and scope without assuming an optimized program preserves every source-level detail.
TypeScriptGoRustCHaskellJavaSanitizers, race detectors, and checked builds
Can a tool catch the bug while it happens? Use AddressSanitizer, go test -race, and Miri to turn silent errors into reports.
CGoRustTests, properties, and repeatability
Build understandingUse examples and generated cases to challenge a claim about behavior.
Test structure and isolated state
How do you make an example repeatable? Compare assertions, fresh fixtures, and language-specific test runners.
TypeScriptGoRustCHaskellJavaTable-driven and parameterized tests
How do you check many cases without copying the test? List inputs and expected results, then report which row failed.
TypeScriptGoRustCHaskellJavaTesting failure paths
Does the code fail the way you promised? Check returned errors, thrown exceptions, and cleanup after a failure.
TypeScriptGoRustCHaskellJavaProperties and generated cases
What should hold over many inputs? Write a property, find a counterexample, and inspect which assumption failed.
TypeScriptGoRustCHaskellJavaClocks, randomness, and test seams
How do you test code that depends on time or external state? Make those dependencies explicit and control them in a test.
TypeScriptGoRustCHaskellJavaContracts, invariants, and safe changes
Build understandingChoose useful boundaries and improve the code while keeping its promises.
Naming and readable code
Will the next reader understand this? Choose names that state intent, and shape code so the common path is easy to follow.
TypeScriptGoRustCHaskellJavaDomain types and smart constructors
Which values should be impossible to construct? Validate at a boundary and use a type or API to preserve the invariant.
TypeScriptGoRustCHaskellJavaAPI contracts and explicit dependencies
What may a caller assume? Describe inputs, outputs, effects, and failure behavior, then choose a dependency boundary that can be tested.
TypeScriptGoRustCHaskellJavaReviewing code and hidden assumptions
What could break with a different caller, input, or lifetime? Review aliasing, ownership, failure paths, and implicit shared state.
TypeScriptGoRustCHaskellJavaRefactoring without changing behavior
Which observations must stay the same? Establish checks before changing the structure, then explain what they do and do not prove.
TypeScriptGoRustCHaskellJavaCost, benchmarks, and profiles
Go underneathMeasure a representative workload before deciding where the cost comes from.
Time, space, and algorithmic cost
How does work grow with input size? Compare asymptotic cost with allocations, constant factors, and the actual workload.
TypeScriptGoRustCHaskellJavaBenchmarking and build modes
What does this timing measure? Account for warmup, optimization, eliminated work, input selection, and measurement noise.
TypeScriptGoRustCHaskellJavaCPU profiles and hot paths
Where is time being spent? Read samples and call paths, form a hypothesis, and measure the change.
TypeScriptGoRustCHaskellJavaAllocation profiles and retained memory
Does this program allocate frequently or keep data alive? Distinguish allocation rate, live memory, and resource leaks.
TypeScriptGoRustCHaskellJava