2026-09-30-shared-mirrors-server-features
title: "The shared package mirrors the server's features, and file length holds in the server and shared packages" affects: dartway_cli: "0.23.0"
Who is affected
Every project whose shared package's lib/src/ holds anything but <feature>.dart or a flat
<feature>/ folder of <feature>_<part>.dart parts, <feature> a feature folder of the server's lib/src/, and the files named after
the package. dart run dartway_cli:dartway check reports each as invalidSharedLayout, an error.
Long files in the server and the shared package are now reported too — fileLong over 200 lines
(info), fileTooLong over 350 (warning) — which fails nothing but tells you where to split. The rule
is in project layout, under my_app_shared.
What to change
Run dart run dartway_cli:dartway check --type invalidSharedLayout; each finding names the file and,
for a near miss, the feature it belongs to. Moving a DTO between files changes nothing on the wire —
its class name is its wire name — but its part '….dw.dart' goes with it: rename the part line in
every file you move or merge, delete the old .dw.dart parts, and run
dart run dartway_cli:dartway generate. Then fix the imports the moves break (dart analyze), and
the export lines of lib/<project>_shared.dart.
- A file named after no server feature (
assignees.dart,quiz_answers.dart,auth_identifier.dart): merge what it declares into the file of the feature whose handlers answer it — a DTO goes where its handler is, and what exists only in the contract goes with the feature that owns it (sign-in rules and the sign-up keys: the feature that creates the profile). There is no sharedcore/to put it in. - A near miss of a feature's name (
course.dartforcourses/,issue_process.dartforissues/): rename it,src/courses.dart, or make it a part,src/issues/issues_process.dart. - A file or folder per concept (
plan/training_catalog.dart,chat_enums.dart):<feature>_<part>.dartinside the feature's folder —src/plan/plan_training_catalog.dart,src/chat/chat_enums.dart. DTOs filed under the wrong feature move to the right one:profile/notification_settings.dart, when the server has anotifications/feature, becomessrc/notifications/notifications_settings.dart. The folder is flat, and a part is never exactly a layer's name (chat_models.dart;content_news_publications.dartis a topic and passes). - A feature folder with a file of its own name (
src/chat/chat.dart): a folder holds parts only — name that file for what it holds (src/chat/chat_channels.dart). - A feature as a file and a folder at once (
src/profile.dartbesidesrc/profile/): split the file into parts inside the folder. - The package-named files. The protocol file (
app_protocol.dart,<project>_wire_protocol.dart) becomes<project>_protocol.dart; the variable it declares keeps its name. A push category enum is<project>_push_category.dart. The channel, refusal and upload files and their enums take the prefix from the package's full name (D-108), so a shared package nameddartway_studio_sharedrenamesstudio_channel.dart,studio_refusal.darttodartway_studio_channel.dart,dartway_studio_refusal.dartand the enumsStudioChannel,StudioRefusaltoDartwayStudioChannel,DartwayStudioRefusal— an IDE rename of the enum reaches the server and the app; the codes on the wire do not change. - Anything else in
lib/beside the library,generated/andsrc/: intosrc/. The library holdslibrary,importandexportdirectives only — a declaration there moves to its feature;generated/holds only what the generator writes; a hand-written file named*.dw.dart,*.g.dartor*.freezed.dartgets the name of what it is.
Splitting a long file — the recipe, by DTO group. A group is a data object with the requests that
read it and the commands that change it; each group becomes one part, and every DTO lands in a part.
For a shared file src/issues.dart of 2400 lines:
mkdir src/issues, then for each group — the issue itself, comments, labels, the process state — createsrc/issues/issues_<group>.dart(issues_core.dartis not a group: name what it holds,issues_records.dart,issues_comments.dart) with the imports it needs andpart 'issues_<group>.dw.dart';, and move the group's classes into it. What the moved classes refer to across groups is imported bypackage:path.- Delete
src/issues.dartandsrc/issues.dw.dartonce they are empty. exportevery new file fromlib/<project>_shared.dart, rundart run dartway_cli:dartway generate, thendart analyzein all three packages.
On the server the same split is <feature>_<part>_<kind>.dart: issues_handlers.dart of 1900 lines
becomes issues_handlers.dart plus issues_comments_handlers.dart, issues_labels_handlers.dart, …,
each exporting its own <DwCallHandler>[…] list, which <feature>_feature.dart joins
(handlers: [...issuesHandlers, ...issuesCommentsHandlers]). A private helper both halves call
becomes a named extension in the feature's logic/.
A seed catalogue that trips the length check: move its rows into a server
<feature>_<part>_rows.dart holding nothing but directives and consts, each a New<Entity>Row(…)
draft or a collection of nothing but drafts — no class, function, final, other constant or helper
call beside them — and the check passes it over as data.
How to check
dart run dartway_cli:dartway check in the Flutter package reports no invalidSharedLayout, and
dart run dartway_cli:dartway generate --check reports nothing stale.