refactor(phase1): conciseness pass — makeEffect, DAE.Snake, combinators#413
Conversation
- Data.Effectful.LLM: makeEffect ''LLM (drop 3 hand-written send wrappers) - Data.Effectful.Wreq: makeEffect ''HTTP — generated effect ops for options/head/optionsWith/headWith now ship from this module instead of re-exporting Network.Wreq's helpers; drop 13 hand-written send wrappers - Replace 44× DAE.CustomJSON '[OmitNothingFields, FieldLabelModifier '[CamelToSnake]] T with the equivalent DAE.Snake T from Deriving.Aeson.Stock (19 files) - Utils.lookupVec*: collapse 5 near-identical helpers into a generic lookupVec / lookupVecBy via FromJSON; keep typed shims for stable callers - Pages.Components: add primaryButton_/ghostButton_/headerRow_/ headerRowPad_/sectionHeader_ combinators; sweep exact-literal call sites - Pages.BodyWrapper: add withPageWrapper/withSettingsPage; migrate Settings.bringS3GetH and GitSync.gitSyncSettingsGetH Deferred from the plan: A3 (table consolidation), D2 text-display migration, attoparsec drop (legit byte-level parser in Replay.hs).
Code ReviewGood, focused refactor — the mechanics are sound and the diff is net negative. A few things worth addressing before merge: 1. Duplicate
|
- Wreq: rename Head -> Head_ so makeEffect generates head_, matching Network.Wreq's convention and protecting downstream callers from shadowing Relude.head when importing this module unqualified - Pages.Components: drop unused ghostButton_ export; make sectionHeader_ a thin alias of headerRow_ so the two can't drift - Models/Projects/Dashboards: unify two Deriving.Aeson.Stock aliases (DAE/DAES) onto DAE; rewrite DAES.Snake call sites Re: the other 8 'duplicate DAE' files flagged in review — verified they all still reference Deriving.Aeson identifiers (CustomJSON, OmitNothingFields, FieldLabelModifier, CamelToSnake, StripPrefix, Rename, ConstructorTagModifier). Both imports are live; ghcid confirms no -Wunused-imports warnings.
Code Review — Phase 1 Conciseness RefactorGood, well-scoped pass overall. The workstreams are independent and the PR description is unusually thorough. A few issues to address before merging. Bug:
|
| Bug | sectionHeader_ duplicate class_ attributes — mb-4 never applied |
| Inconsistency | Widget.hs uses DAES.Snake instead of the standardised DAE.Snake |
| Cleanup | Drop redundant import Deriving.Aeson qualified as DAE in files where only DAE.Snake is used |
| OK | makeEffect workstream, DAE.Snake sweep, lookupVec refactor, withPageWrapper/withSettingsPage helpers |
Prevents token collision if a caller's appended class_ attribute butts up against ours when Lucid concatenates multiple class attributes. Also: drop type SnakeJSON alias in Web/ApiTypes; use DAE.Snake directly at the 26 call sites.
Code Review — refactor/phase1-concisenessOverall this is a clean, well-scoped refactor. Bug:
|
Code Review — Phase-1 Conciseness RefactorOverall this is a well-scoped, clean refactor. The mechanical substitutions (Workstreams B, C, D1) are correct and the reduction from 382 lines to 173 is meaningful. A few issues to address before merging. Bug:
|
…nup, head_ - Components: sectionHeader_ inlines the full class string (Lucid emits two class= attrs when concatenated, which browsers treat as invalid and drop the second — mb-4 was silently being lost) - Widget.hs: rename DAES -> DAE alias to match the rest of the codebase - Drop redundant 'Deriving.Aeson qualified as DAE' import in 9 files where 'Deriving.Aeson.Stock qualified as DAE' (which re-exports the Aeson surface) covers all uses - Drop type SnakeJSON alias from Web/ApiTypes; use DAE.Snake at the 26 call sites directly - Wreq: rename Head -> Head_ so makeEffect generates head_, matching Network.Wreq's head_ convention (avoids shadowing Relude.head for unqualified importers)
Code ReviewWell-executed conciseness pass. Net −46 lines across 29 files with no semantic changes — this is exactly the kind of refactor the codebase benefits from. A few things worth discussing:
|
PR #413 swapped `Deriving.Aeson` for `Deriving.Aeson.Stock` in 10 files that still reference building blocks (OmitNothingFields, FieldLabelModifier, CamelToSnake, ConstructorTagModifier, StripPrefix, Rename). `.Stock` doesn't re-export them in 0.2.10, so cold ghcid reloads fail with GHC-76037. Add back `Deriving.Aeson qualified as DAE` alongside the existing Stock import. Also: make `Pages.BodyWrapper.withSettingsPage` take an effectful builder so handlers can do DB/HTTP work for the body; migrate `GitSync.githubAppReposH`.
Summary
Phase-1 conciseness refactor from
~/Downloads/refactorphase1conciseness.md. Pure refactor — rendered HTML / JSON wire format / effect semantics are unchanged. Build green (ghcid: 110 modules loaded).Workstream B (effects):
Data.Effectful.LLM:makeEffect ''LLMreplaces 3 hand-writtensendwrappers.Data.Effectful.Wreq:makeEffect ''HTTPreplaces 13 hand-written wrappers. The previously re-exportedNetwork.Wreq.options/head_/optionsWith/headWithare dropped —makeEffectnow exposes the effect-leveloptions/head/optionsWith/headWithfrom this module.Reludehidesheadso the generated name resolves cleanly. Zero callers used the old Wreq-level re-exports (confirmed via rg).Workstream C (JSON deriving):
SnakeOmitalias once @tonyalaribe pointed outDeriving.Aeson.Stockalready exportsSnake. Replaced 44×DAE.CustomJSON '[OmitNothingFields, FieldLabelModifier '[CamelToSnake]] Twith the equivalentDAE.Snake Tacross 19 files. AddedDeriving.Aeson.Stock qualified as DAEwhere missing.Workstream D1 (lookup helpers):
src/Utils.hs: 5 near-identicallookupVec*helpers collapsed into a genericlookupVec/lookupVecByviaFromJSON; the existing typed shims (lookupVecText,lookupVecInt,lookupVecTextByKey, …) remain as one-liners so callers don't move.Workstream A (view-layer combinators) — partial:
Pages.ComponentsgainedprimaryButton_,ghostButton_,headerRow_,headerRowPad_,sectionHeader_.button_ [class_ "btn btn-primary btn-sm"…]and"flex items-center justify-between"family). Variant-class sites (extra Tailwind tokens) intentionally left alone in this pass — they can be folded in once the combinator pattern is established.Pages.BodyWrapper: addedwithPageWrapper/withSettingsPage. MigratedSettings.bringS3GetHandGitSync.gitSyncSettingsGetHas proof-of-concept; remainingmkPageCtx/bodyWrapperhandlers can move incrementally.Deferred from the plan (call out for follow-ups):
attoparsecis the right tool forsplitReplayPayload(byte-level streaming JSON parser) so it stays.Test plan
ghcidgreen (110 modules,All good)fourmolu -ion changed filesmake lintproduced only pre-existing hints (none in touched files)make test-unit(not run here — please verify in CI)make test-integration(not run here — please verify in CI)