Files

295 lines
14 KiB
Markdown

# Less Code
This document records a measured plan for reducing WeKan's maintained source
code without removing supported behaviour, translations, accessibility or
tests. Fewer lines are useful only when they also leave fewer independent
implementations to understand and keep consistent.
## Baseline
Measured on 2026-09-03 from JavaScript, Jade, CSS and MJS files below
`client/`, `server/`, `imports/` and `models/`:
| Source | Files | Lines |
| --- | ---: | ---: |
| JavaScript and MJS | 798 | 150,724 |
| CSS | 73 | 28,941 |
| Jade | 111 | 13,287 |
| Total | 982 | 192,952 |
Generated bundles, dependencies, translation JSON and tests are not included.
The baseline is a navigation aid rather than a target to game: moving code to
generated files or compressing formatting does not count as a reduction.
The largest promising areas found in the initial survey are:
| Area | Current evidence | Opportunity |
| --- | --- | --- |
| Board themes | `boardColors.css` is 6,339 lines | Store theme values once and share structural rules |
| Language registry | `languages.js` is 1,724 lines | Generate repetitive registry entries from compact metadata |
| Large UI controllers | Several files have 1,400-2,900 lines | Extract genuinely repeated paging, forms and actions |
| Authorization | Rules occur in models, methods, publications and REST routes | Use one policy function per operation |
| Importers | Creator modules repeat entity creation pipelines | Normalize input, then persist through one pipeline |
| Retired paths | Dynamic Blaze references hide some unused code | Remove only with runtime and test evidence |
Splitting a large file, changing Jade to Svelte, minifying source, or moving
logic into a dependency does not by itself satisfy this plan.
## Working rules
Each phase is completed and verified before the next begins. Record its before
and after measurements below. Behavioural changes need positive and negative
tests; visible changes also need an applicable UI or screenshot test. Preserve
special cases instead of forcing them into an abstraction that makes the code
harder to understand.
Small migrations are preferred. A phase may be stopped when measurement shows
that its abstraction adds more complexity than it removes.
## Phase 1: board theme declarations
`client/components/boards/boardColors.css` repeats selectors and declarations
for every named theme. Introduce shared structural rules backed by CSS custom
properties, while retaining explicit overrides for gradients, image themes,
Apple Glass Pastel and other exceptional designs.
Steps:
1. Inventory the property roles used by ordinary colour themes and classify
exceptional themes.
2. Add a shared rule set and a small variable declaration for one ordinary
theme.
3. Extend the existing theme tests so they verify computed outcomes rather
than requiring the old repeated selector layout.
4. Migrate ordinary themes in small batches and run the theme, header, public
board, All Boards and checkbox tests after each batch.
5. Compare CSS size and a representative rendered board in desktop and mobile
widths. Keep special-theme CSS explicit where that is clearer.
Acceptance criteria:
- all existing visual behaviours and theme choices remain available;
- theme tests and relevant Playwright tests pass;
- `boardColors.css` has materially fewer declarations and bytes;
- a new ordinary solid-colour theme can be added mainly by declaring values.
Result:
- ten ordinary solid-colour themes now declare twelve palette values and use
one shared structural rule set;
- gradient, image, Relax, Dark, Apple Glass Pastel, Modern and Clean themes
remain explicit because their structure or behaviour differs;
- `boardColors.css` decreased from 6,339 lines / 196,012 bytes / 1,266 rules /
2,216 declarations to 5,895 lines / 178,134 bytes / 1,058 rules / 2,064
declarations;
- PostCSS parsed the resulting stylesheet successfully;
- `themeAccents`, `boardTileTheme`, `allBoardsPage`, `publicBoardsPage`,
`headerBars`, `checkboxesAreSquare` and `appleGlassPastelTheme` passed: 110
assertions in total;
- a Chromium computed-style check was attempted at 1,280 px and 390 px, but
this ARM64 sandbox only has an x86-64 Chromium binary and its emulated launch
did not complete. Runtime visual verification therefore remains an
environment boundary rather than a claimed result.
Status: **completed** in commit `cd1039230`.
## Phase 2: language metadata
Replace repetitive hand-written language registry objects with compact
metadata and generated lazy imports. The public registry shape and language
order must remain unchanged. Adding a language must still require all three
integration points specified by the translation policy.
Acceptance criteria:
- every current locale is registered with the same code, tag, native name and
RTL value;
- every translation remains lazily loaded;
- translation, key-order, placeholder and language-picker tests pass;
- the authoritative metadata is shorter and has a duplicate-tag check.
Result:
- the 245 language records now use one compact metadata row each;
- a separate loader map retains one literal dynamic `import()` per language,
preserving Meteor's per-language split points;
- a runtime parity comparison against the previous module confirmed identical
keys, codes, tags, native names, RTL flags and loader paths for all 245
entries;
- `languages.js` decreased from 1,724 lines / 34,873 bytes to 510 lines /
24,362 bytes;
- guards now reject duplicate metadata keys, duplicate language tags, duplicate
loader keys, missing loaders, eager imports and files not claimed by the
registry;
- `i18nLazyLoading`, `i18nLazyLoaded`, `newLanguageWiring`, `rtl` and
`changeLanguageColumns` passed: 31 assertions in total.
Status: **completed** in commit `a3bc8155d`.
## Phase 3: repeated UI mechanics
Measure duplication in large UI files before extracting anything. Concentrate
on repeated pagination, searches, menu data, modal lifecycle, form value
collection and Meteor method result handling. Do not create generic helpers for
code that merely looks similar but has different behaviour.
Acceptance criteria:
- at least two real consumers use every extracted abstraction;
- user-visible error, keyboard and accessibility behaviour is preserved;
- focused unit tests cover the shared primitive and UI tests cover consumers;
- total maintained code is lower after including the new abstraction.
Result:
- one `adjacentPage` primitive now clamps page movement for All Boards, the
generic Admin Panel reports, event streams, office reports and all four
People paging contexts;
- People maps the active pane to its page, total and page-size state once,
replacing separate previous/next branches for organizations, teams, people
and the login-location drill-down;
- focused tests cover ordinary movement, both boundaries, normalized direction
and invalid movement; the existing consumer suites passed with 96 assertions
(`tablePage` 55, `allBoardsPage` 27, subscription lifetime 3 and grouped
offices 11);
- the 982-file maintained-source measurement decreased from 191,284 to 191,279
lines. The small five-line net reduction includes the new shared primitive;
tests are excluded from that measurement and grew to pin its behaviour.
Status: **completed** in commit `eb0e34786`.
## Phase 4: authorization policies
Inventory equivalent permission decisions across collection methods, Meteor
methods, publications and REST endpoints. Move each equivalent decision into a
pure shared policy and retain transport-specific error formatting at the edge.
Acceptance criteria:
- DDP and REST make the same decision for the same actor and resource;
- policies have allowed and denied tests, including missing resources;
- publications do not expose records rejected by their matching mutation
policy;
- duplicated permission conditions are removed rather than wrapped.
Result:
- the existing write-capability policy was confirmed to serve collection
permissions, Meteor methods, REST mutations and destination checks in
publications; it was retained instead of creating a competing abstraction;
- a new transport-neutral `canReadBoard` policy now serves two DDP
publications, two HTTP attachment routes and fourteen position-history
method checks;
- public boards allow anonymous and authenticated reads, private boards require
an active member, and missing or malformed boards fail closed;
- HTTP and DDP keep their own response/error formatting at their edges. The
legacy attachment publication now makes the same public-board decision as
the HTTP download routes instead of rejecting every anonymous subscriber;
- six focused policy and wiring tests passed, together with the existing file
safety, request authentication, card scope and window-publication suites;
- maintained source decreased from 191,279 to 191,248 lines, including the new
policy module.
Status: **completed** in commit `e8c867b33`.
## Phase 5: importer pipeline
Define a small internal board representation for importers. Source-specific
modules parse and normalize their data; one tested writer creates users,
boards, swimlanes, lists, cards, comments, checklists and attachments.
Acceptance criteria:
- existing supported import formats retain their behaviour;
- source-specific quirks remain visible in their adapters;
- malformed and partial imports have negative tests;
- entity creation and ID-mapping logic has one implementation where possible.
Result:
- WeKan JSON and Trello adapters now describe their ordered stages to one
`runImportPipeline` implementation, which carries the created board ID and
normalizes absent optional collections to empty arrays;
- one `writeImportedEntity` implementation now owns direct insertion, optional
timestamp touching and old-to-new ID recording for lists, swimlanes,
checklists and WeKan custom fields;
- source-specific normalization remains in the adapters: notably WeKan's real
swimlanes and extra dependency/rule stages, and Trello's synthetic default
swimlane and inline checklist items;
- malformed top-level input and a pipeline that creates no board fail closed;
missing optional arrays, stage order, ID propagation, mapping and timestamp
writes have focused positive and negative tests;
- six pipeline tests and 95 existing importer assertions passed. The three
changed modules also passed Node 24 syntax checks;
- maintained source decreased from 191,248 to 191,220 lines, including the new
pipeline module. Obsolete commented-out importer implementations and the
unused empty WeKan checker were removed as part of the same inventory.
Status: **completed** in commit `8b7115335`.
## Phase 6: evidence-based removal
Run static analysis as a candidate generator, then verify candidates against
Blaze template names, dynamic imports, global registrations, server startup
side effects and packaging entry points. Remove retired compatibility paths
and unused feature code only after that inspection.
Acceptance criteria:
- every removal has search evidence and relevant regression coverage;
- application startup, production build and registered test suites succeed;
- no supported deployment mode or documented feature is silently removed.
Result:
- static search found two tracked model implementations whose `.disabled`
suffix prevents Meteor from treating them as JavaScript. No import, template,
startup registration, package entry or application source referenced their
filenames or `AttachmentsOld` / `AvatarsOld` symbols;
- `models/attachments_old.js.disabled` and
`models/avatars_old.js.disabled` were removed: 148 tracked lines. These files
are recoverable from git history;
- supported legacy CollectionFS reads remain in
`attachmentBackwardCompatibility.js`, the legacy attachment publication and
its HTTP route. Migration extraction and file-safety suites passed;
- a regression test verifies that the retired files and symbols stay absent
while the active legacy-read modules remain present;
- all 709 registered Node test suites passed with zero failures in 48 seconds;
- `meteor build .build-lesscode --directory` completed successfully. Its only
diagnostics were existing asset-size and optional MongoDB dependency
warnings;
- a development startup with a temporary `WRITABLE_PATH` reached `Started your
app` and served at `http://127.0.0.1:3999`, after which it was stopped cleanly;
- the maintained-source metric is unchanged at 191,220 because `.disabled`
files were deliberately excluded from that baseline. The removal nevertheless
deletes 148 tracked, reviewable lines rather than moving or compressing them.
Status: **completed** in commit `e37717d07`.
## Results
| Phase | Before | After | Tests | Result |
| --- | ---: | ---: | --- | --- |
| Baseline | 192,952 lines | 191,220 lines | Not applicable | 1,732 fewer maintained lines |
| 1. Board themes | 6,339 lines / 196,012 bytes | 5,895 lines / 178,134 bytes | 110 assertions passed; browser unavailable | Completed (`cd1039230`) |
| 2. Language metadata | 1,724 lines / 34,873 bytes | 510 lines / 24,362 bytes | Registry parity and 31 assertions passed | Completed (`a3bc8155d`) |
| 3. UI mechanics | 191,284 maintained lines | 191,279 maintained lines | Primitive and 96 consumer assertions passed | Completed (`eb0e34786`) |
| 4. Authorization | 191,279 maintained lines | 191,248 maintained lines | 6 policy tests plus transport regressions passed | Completed (`e8c867b33`) |
| 5. Importers | 191,248 maintained lines | 191,220 maintained lines | 6 pipeline and 95 importer assertions passed | Completed (`8b7115335`) |
| 6. Removal | 148 tracked disabled lines | 0 tracked disabled lines | 709 Node suites, build and startup passed | Completed (`e37717d07`) |
## Final outcome
All six phases are complete. The maintained JavaScript/MJS, Jade and CSS metric
decreased from 192,952 to 191,220 lines: **1,732 fewer maintained lines**. Phase
6 additionally removed 148 tracked disabled lines that were outside the
baseline, for **1,880 deleted or avoided lines** across the measured work.
The reductions came from fewer independent implementations, not from
minification or changing template technology. Replacing all Jade/Blaze views
with Svelte would temporarily increase code because both UI systems, adapters
and migration tests would coexist; it is therefore not a code-reduction step by
itself. Further work should repeat this measured approach on one duplicated
behavior at a time and retain a change only when its tests and maintenance
surface improve.