A change reveals a boundary
A program validates grades, calculates averages, formats reports and prints them in one long file. The passing threshold changes. Which part should change, and which should remain unaffected?
Start by separating responsibilities conceptually before moving files:
| Responsibility | Example module | Depends on |
|---|---|---|
| Validate grade values | validation.js | Agreed grade scale |
| Calculate averages | calculations.js | Valid grade values |
| Apply student policies | students.js | Calculations and thresholds |
| Coordinate and display | main.js | The public functions above |
A module is a file with an explicit interface of exports and imports. It is not merely a smaller arbitrary slice of a giant file. Keep related policy together and avoid a universal utilities file that accumulates unrelated operations.
Guided design review
Moving every function into its own file can increase navigation without clarifying responsibility. Group a few related functions first. If two modules require each other to initialize, reconsider the dependency direction instead of accepting a confusing cycle.
The direction above allows the main program to use calculation logic without making the calculation import display behavior. This makes it easier to reuse and test.
Independent exercise
Assign these operations to responsibilities: validate a price, calculate subtotal, format a label, choose a loyalty discount and print the final report. Explain where the business threshold should live.
Correction
Validation checks the price; calculations computes subtotal; a formatting or presentation responsibility creates the label; policy logic chooses loyalty eligibility; main coordinates and prints. Keep the threshold next to the eligibility rule or pass it as an explicit policy input. Do not duplicate it in display and calculation files.
Review
Write a dependency list before moving code. A useful module boundary lets you describe what it provides without reading its internal implementation. In the next lesson, create a runnable two-file example using named exports.