When I was building my music app in Flutter, I began with the “quick and dirty” way of handling data. You know that vibe coding flow — fetch some JSON, dump it in a Map<String, dynamic>, and just wire it up to the UI. It felt fast at first, but it quickly turned into a mess.
Take this example: I was fetching playback data from my service and passing it around like this:
class PlaybackWidget extends StatelessWidget {
final Map<String, dynamic> playbackData;
PlaybackWidget({required this.playbackData});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Now playing: ${playbackData['title']}"),
Text("Artist: ${playbackData['artist']}"),
Text("Mode: ${playbackData['playbackMode']}"),
],
);
}
}
It worked. But every time I typed playbackData['title'], I felt uneasy. One typo like playbackData['titel'] and boom — runtime error. On top of that, the widget didn’t tell me what kind of data it really expected. Was playbackMode a string? An enum? A number? I had to keep it all in my head.
Switching to Models
After wrestling with this a few times, I finally decided to create a proper model for my playback data.
enum PlaybackMode { repeat, shuffle, normal }
class Playback {
final String title;
final String artist;
final PlaybackMode playbackMode;
Playback({
required this.title,
required this.artist,
required this.playbackMode,
});
factory Playback.fromJson(Map<String, dynamic> json) {
return Playback(
title: json['title'],
artist: json['artist'],
playbackMode: PlaybackMode.values.firstWhere(
(e) => e.toString() == 'PlaybackMode.${json['playbackMode']}',
),
);
}
Map<String, dynamic> toJson() {
return {
'title': title,
'artist': artist,
'playbackMode': playbackMode.name,
};
}
}
Now my widget looked much cleaner:
class PlaybackWidget extends StatelessWidget {
final Playback playback;
PlaybackWidget({required this.playback});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text("Now playing: ${playback.title}"),
Text("Artist: ${playback.artist}"),
Text("Mode: ${playback.playbackMode.name}"),
],
);
}
}
Suddenly everything felt safer. Autocomplete worked, I didn’t worry about typos, and my code told me exactly what kind of data I was dealing with.
What I Learned
Models might look like “extra code” at first, but in reality, they save time and mental energy. Instead of juggling raw maps everywhere, you give your app a solid data structure to lean on.
In my case, once I switched to models in my music app, my code got way easier to maintain. Adding new fields, refactoring, or passing data between widgets stopped being a headache.
So if you’re just hacking away in Flutter and think models are overkill — trust me, they’re not. Future-you will thank present-you for adding them.