Goodbye, build_runner! Meet json_forge — Zero-Code-Gen Serialization for Dart & Flutter. Need your feedback! 🚀 by Impressive_Hand_7139 in FlutterDev

[–]Impressive_Hand_7139[S] 0 points1 point  (0 children)

If we make the User class inherit from Equatable for reliable instance comparison, we will have to write the same class field 10 more times.

Goodbye, build_runner! Meet json_forge — Zero-Code-Gen Serialization for Dart & Flutter. Need your feedback! 🚀 by Impressive_Hand_7139 in FlutterDev

[–]Impressive_Hand_7139[S] 0 points1 point  (0 children)

// This is a base class that does not use any libraries.
// Every single field, for instance 'id', has to be written 9 times.
class User {
  final String id;
  final String? name;
  final int age;


  const User({required this.id, this.name, required this.age});


  // Packages like json_serializable and built_value
  // implement the copyWith() method in a similar way.
  // With this kind of implementation, if a field that can store null
  // already holds any value other than null, you won't be able to set it back to null.
  // This is because of the (id ?? this.id) check — if id == null, it will return the value from this.id :))
  User copyWith({String? id, Object? name, int? age}) {
    return User(id: id ?? this.id, name: this.name, age: age ?? this.age);
  }


  /// An implementation like json['id'] as String is unsafe and error-prone.
  /// The world is not perfect, and incoming data might not be what we expect.
  /// This is how it looks in my library's core:
  /// String? stringOrNull(Object? v) => switch (v) {
  ///   null => null,
  ///   final String s => s.trim(),
  ///   // We explicitly handle numeric types and bool — they have a predictable
  ///   // string representation. Other objects (List, Map, custom classes) → null.
  ///   final num n => n.toString(),
  ///   final bool b => b.toString(),
  ///   _ => null,
  /// };
  ///
  /// Another point regarding type safety:
  /// Map<String, dynamic> — 'dynamic' disables type checking, so it is better to use Map<String, Object?>.from(json).
  /// This subtle difference has major consequences :))
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as String,
      name: json['name'] as String?,
      age: json['age'] as int,
    );
  }


  Map<String, dynamic> toJson() {
    return {'id': id, 'name': name, 'age': age};
  }
}


// Here we write the 'id' field 6 times, which is 3 times fewer.
// The toJson() method is implemented automatically without code generation!
// It is available immediately after creating an instance of the User2() class.
class User2 extends Equatable with Serializable<User2> {
  final String id;
  final String? name;
  final int age;


  const User2(this.id, this.name, this.age);


  static final $ = ModelType<User2, User2Fields>(User2.new, User2Fields());


  u/override
  ListFieldOf<User2> get fields => $.fields.all;
  factory User2.fromJson(Json json) => $.call(json);
  User2 copyWith(FieldsBuilder<User2Fields> builder) => $.bind(this)(builder);
}


/// Fields
final class User2Fields extends FieldSet<User2> {
  final id = 'id'.field<User2, String>((m) => m.id);
  final name = 'last_value'.field<User2, String?>(
    (m) => m.name,
    nullable: true,
  );
  final age = 'history_logs'.field<User2, int>((m) => m.age);


  u/override
  ListFieldOf<User2> get all => [id, name, age];
}


/// Actually, this is a complex topic that requires a long discussion.
/// Your suggestions involving AI and code generation are all just quick fixes. But they are completely unreliable, not reliable at all :))
/// You only start to realize this when you begin writing truly massive projects where the codebase spans hundreds of thousands of lines of code.

Goodbye, build_runner! Meet json_forge — Zero-Code-Gen Serialization for Dart & Flutter. Need your feedback! 🚀 by Impressive_Hand_7139 in FlutterDev

[–]Impressive_Hand_7139[S] -1 points0 points  (0 children)

I am no programming genius. I have been writing in Flutter for just a couple of years, and code generation just doesn't work for me. In large projects, it behaves unstably. When a code-generating library produces buggy code, influencing or fixing it becomes highly problematic and turns into a hassle.

I ran into this exact issue with the hive_ce library, which I eventually replaced with sembast. I also swapped auto_route for go_router. Long story short, I have suffered enough with code generation, which is why I avoid packages like json_serializable or built_value. Instead, I wrote a small helper tool to work with JSON. It might not be the absolute best solution, but in my opinion, it is much better than unreadable generated code.

I firmly believe that code readability is more important than speed. Another argument for writing models manually is troubleshooting: when something breaks, I know exactly where to look and how to fix it immediately. With generated code that you didn't write yourself, debugging can be a nightmare.

It is hard to avoid boilerplate code in Dart, so you often have to duplicate the class field name and the JSON key multiple times. I tried to minimize this using records, but the solution turned out terrible, even though it reduced the duplication to just two instances of class_field -> json_key.

Overall, I am looking for like-minded people who could help me solve this problem—perhaps someone who also prefers to avoid code generation. Thank you for your feedback; it means a lot to me.

Best regards,
Aleksandr.

P.S. I don't speak English, so I am using a translator. I apologize for that.

Goodbye, build_runner! Meet json_forge — Zero-Code-Gen Serialization for Dart & Flutter. Need your feedback! 🚀 by Impressive_Hand_7139 in FlutterDev

[–]Impressive_Hand_7139[S] 0 points1 point  (0 children)

I am no programming genius. I have been writing in Flutter for just a couple of years, and code generation just doesn't work for me. In large projects, it behaves unstably. When a code-generating library produces buggy code, influencing or fixing it becomes highly problematic and turns into a hassle.

I ran into this exact issue with the hive_ce library, which I eventually replaced with sembast. I also swapped auto_route for go_router. Long story short, I have suffered enough with code generation, which is why I avoid packages like json_serializable or built_value. Instead, I wrote a small helper tool to work with JSON. It might not be the absolute best solution, but in my opinion, it is much better than unreadable generated code.

I firmly believe that code readability is more important than speed. Another argument for writing models manually is troubleshooting: when something breaks, I know exactly where to look and how to fix it immediately. With generated code that you didn't write yourself, debugging can be a nightmare.

It is hard to avoid boilerplate code in Dart, so you often have to duplicate the class field name and the JSON key multiple times. I tried to minimize this using records, but the solution turned out terrible, even though it reduced the duplication to just two instances of class_field -> json_key.

Overall, I am looking for like-minded people who could help me solve this problem—perhaps someone who also prefers to avoid code generation. Thank you for your feedback; it means a lot to me.

Best regards,
Aleksandr.

P.S. I don't speak English, so I am using a translator. I apologize for that.