⚠️ Malware / Trojaner / VirenAndroid-Malware blockiert Google Play per VPN-Trick(24.08.2026 um 13:00 Uhr)
🪟 Windows TippsWindows 11: Falsche Defender-Warnungen und kaputte Mauszeiger(31.08.2026 um 11:58 Uhr)
🕵️ SicherheitslückenDropbox-Hack: Tausende Konten kompromittiert(02.09.2026 um 11:02 Uhr)
⚠️ Malware / Trojaner / VirenAtombomben-Frage trickst KI-Malware-Scanner aus(02.09.2026 um 12:46 Uhr)
🪟 Windows TippsMehr Sicherheit in Windows 11(03.09.2026 um 11:51 Uhr)
⚠️ Malware / Trojaner / VirenNeue Android-Malware schreit Sie an, wenn Sie nicht zahlen(11.09.2026 um 10:33 Uhr)
🐧 Linux TippsMehrere Probleme in freerdp2 (Fedora)(11.09.2026 um 23:24 Uhr)
🐧 Linux TippsMehrere Probleme in kamailio (Debian)(11.09.2026 um 23:28 Uhr)
🐧 Linux TippsAusführen beliebiger Kommandos in dokuwiki (Fedora)(11.09.2026 um 23:28 Uhr)
🐧 Linux TippsAusführen beliebiger Kommandos in python-asteval (Fedora)(11.09.2026 um 23:28 Uhr)
⚠️ Malware / Trojaner / VirenAndroid-Malware blockiert Google Play per VPN-Trick(24.08.2026 um 13:00 Uhr)
🪟 Windows TippsWindows 11: Falsche Defender-Warnungen und kaputte Mauszeiger(31.08.2026 um 11:58 Uhr)
🕵️ SicherheitslückenDropbox-Hack: Tausende Konten kompromittiert(02.09.2026 um 11:02 Uhr)
⚠️ Malware / Trojaner / VirenAtombomben-Frage trickst KI-Malware-Scanner aus(02.09.2026 um 12:46 Uhr)
🪟 Windows TippsMehr Sicherheit in Windows 11(03.09.2026 um 11:51 Uhr)
⚠️ Malware / Trojaner / VirenNeue Android-Malware schreit Sie an, wenn Sie nicht zahlen(11.09.2026 um 10:33 Uhr)
🐧 Linux TippsMehrere Probleme in freerdp2 (Fedora)(11.09.2026 um 23:24 Uhr)
🐧 Linux TippsMehrere Probleme in kamailio (Debian)(11.09.2026 um 23:28 Uhr)
🐧 Linux TippsAusführen beliebiger Kommandos in dokuwiki (Fedora)(11.09.2026 um 23:28 Uhr)
🐧 Linux TippsAusführen beliebiger Kommandos in python-asteval (Fedora)(11.09.2026 um 23:28 Uhr)

🔧 Programmierung 🕛 vor 1 Monat 5 Min Lesezeit
0

How I Made Features in a Large Flutter App Actually Removable

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

"Just delete the features you don't need" is the easiest thing in the world to write in a README, and the hardest to make true.



I hit this building a Flutter app with six verticals in one codebase — marketplace, ride-hailing, car rentals, social feed, chat, wallet. Deleting one should have been simple. It wasn't, because every feature had tendrils:




  • a route in the central route table

  • a tab hardcoded in the app shell

  • a button on the home screen

  • a service registered in main()



Remove the feature folder and you get a wall of compile errors from files that have nothing to do with it. Here's what actually worked.






Make three things data instead of code






1. Routes



Each feature exposes its own routes from its own folder:




CODE
class WalletModule extends AppModule {
const WalletModule();

@override
String get id => 'wallet';

@override
List<GetPage> get pages => [
GetPage(name: AppRoutes.wallet, page: () => const WalletScreen()),
];
}






The app's route table becomes a composition:




CODE
static final routes = <GetPage>[
..._centralRoutes,
...ModuleRegistry.pages,
];






Adding or removing a feature stops being an edit to a shared file. It's one line in a registry.






2. Bottom-navigation tabs



This one surprised me. My app shell imported the feed widget directly:




CODE
// before — the always-present shell depends on an optional feature
import '../feed/feed_tab.dart';






The shell ships in every build. That import meant the social feature could never be removed.



So a tab became a small data class that a feature contributes:




CODE
class ShellTab {
final String id;
final int order; // core tabs use 10/30/40
final IconData icon;
final String labelKey;
final Widget Function() builder;
}






Social contributes its tab at order 20, slotting between home and alerts without the shell knowing it exists. The shell merges its own tabs with ModuleRegistry.shellTabs and sorts.






3. Entry points



Home screens linked to feature screens with Get.toNamed(...). Named routes are already decoupled — no import needed — but navigating to a route that isn't registered just fails silently.



So the route table answers questions about itself:




CODE
static final Set<String> _names = {for (final p in routes) p.name};

static bool hasRoute(String route) => _names.contains(route);






And the UI asks before offering:




CODE
if (AppPages.hasRoute(AppRoutes.cart))
ServiceTile(label: 'Cart', onTap: () => Get.toNamed(AppRoutes.cart)),






A build without the module simply doesn't show the button, instead of showing one that goes nowhere.






Two things I got wrong



Both were embarrassing, and both took one line to fix once I actually looked.



A home layout imported an entire feature to format a date. There was a feedRelativeTime() helper living inside feed_tab.dart, and the home screen used it. That single import made the social feature non-removable. Moving the helper to shared/ removed the dependency completely — it was never real coupling, just misplaced code.



Another layout imported a map controller for two numbers. A static const default latitude and longitude. Same fix.



If you try this on your own codebase, look for these first. A surprising amount of "architectural coupling" is just something sitting in the wrong file.






Navigation is not the same as capability



The subtler bug came later. My checkout screen offered "pay with wallet" unconditionally.



In a build without the wallet module, that option still worked — the service was still registered in main(), the balance was real. There was just no wallet screen to open. A payment method with nowhere to top up.



hasRoute was the wrong question. It answers "can I navigate there?" What I needed was "is this feature in the build?":




CODE
ModuleRegistry.isEnabled('wallet')   // is this FEATURE here?
AppPages.hasRoute(AppRoutes.wallet) // can I navigate there?






Conflating those two is exactly how you ship a payment option you can't support.



This is also why I stopped trying to move shared services into modules. WalletService and CartService are used by several features and stay registered centrally — they're cheap and always resolvable. What must not leak is the UI for a feature that isn't installed.






How I know it works



The part that made this trustworthy isn't the architecture, it's the test.



I remove modules from the registry and rebuild, then assert:




  • the app still analyzes clean — no dangling references

  • the route count drops by exactly the number that module owned

  • the tab bar loses exactly the tabs it contributed


  • isEnabled reports it absent



Dropping the marketplace module takes the app from 38 routes to 30, removes the Shopping home layout from Settings entirely, and falls back to the all-in-one layout if that's what the user had saved. A storefront home screen with no store is worse than not offering it.



Claims about modularity are cheap. Deleting things and watching the build stay green is not.






What I haven't solved



Repositories live in a shared data/ layer, which is what lets home screens preview any feature. That's a deliberate trade for legibility, but it means deleting a feature folder outright still needs its repository registration removed from main().



Someone on r/FlutterDev suggested an event bus — modules fire events instead of calling each other, and a base module routes them. It's a genuinely better answer for cross-module communication. The trade-off is compile-time safety: you can't see who handles an event, or whether anyone does, and tracing a flow becomes grepping for string keys. For a codebase other people have to read quickly, I'm not sure that's the right trade. Still thinking about it.






This came out of building Paragon, a Flutter template. The demo is open if you want to poke at it — no signup.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Stealing AI Reasoning Traces
1 Quelle
AIs as Modern Genies
1 Quelle
Bitcoin: KI-Hacker räumen Millionen ab! Wird Künstliche Intelligenz zum Problem? - ftd.de