boskokg/flutter_blue_plus

[Question] 19 dependencies seems excessive. Are all really needed?

Closed this issue · 4 comments

Flutter Blue Plus uses 19 dependencies. Edit: actually I misunderstood the output of pub add, Im not sure the real number, including child dependencies.

As we all know, more dependencies == things break more often == more maintenance == more work!

Can you provide guidance on what these are used for? It would be great to get rid of any unneeded dependencies.

I would be happy to help.

dependencies:
  flutter:
    sdk: flutter
  convert: ^3.0.1
  protobuf: ^2.0.1
  rxdart: ^0.27.5
  collection: ^1.15.0
  meta: ^1.7.0

flutter pub add flutter_blue_plus
Resolving dependencies...
  async 2.10.0 (2.11.0 available)
  characters 1.2.1 (1.3.0 available)
  collection 1.17.0 (1.17.1 available)
+ convert 3.1.1
+ fixnum 1.1.0
+ flutter_blue_plus 1.4.0
  intl 0.17.0 (0.18.0 available)
  js 0.6.5 (0.6.7 available)
  matcher 0.12.13 (0.12.15 available)
  material_color_utilities 0.2.0 (0.3.0 available)
  meta 1.8.0 (1.9.1 available)
  path 1.8.2 (1.8.3 available)
  path_provider_android 2.0.24 (2.0.25 available)
  path_provider_foundation 2.2.1 (2.2.2 available)
+ protobuf 2.1.0
+ rxdart 0.27.7
  source_span 1.9.1 (1.10.0 available)
  test_api 0.4.16 (0.5.1 available)
  win32 3.1.4 (4.1.3 available)
Changed 5 dependencies!

My findings:

Could easily be removed (in order of ease):

  • meta: used for a single @immutable annotation in CharacteristicProperties
  • convert: used to encode & decode a few hex strings. Using this library only saves like 10 lines of code...
  • collection: only used for compareAsciiLowerCase and ListEquality to hash a list. Again, saves like 10 lines of code...
  • rxdart: used for a singleBehaviorSubject stream, just to cache the most recent value.

Required:

  • flutter: needed for MethodChannel and EventChannel, which are expected / really helpful for platform native extensions.

Difficult to remove:

  • protobuf: Of course, we always want tooling for codegen -- it's great for this use case. But do we need protobuf as a runtime dependency? Possibly not. I think if the generated serialization code used the JSON wire-format option, then the generated code might be free-standing using only standard libraries like org.json in Java, JSONSerialization in Swift, and jsonDecode in Dart. But I am not sure. (Edit: looks like it stills generates very protobuf specific code, lame.) In lieu of that, OpenAPI's generated Dart code just uses json_serializable, and generates really idiomatic Java & Swift code with no dependencies on either platform. Obviously this is a full day's work and maybe not worth the effort, though. But the more I read OpenAPI's generated code, the more I like it! So idiomatic and clean! Edit: See my next comment for an example.

With minimal effort, we could have flutter & protobuf as our only dependencies. And with a bit more effort, only flutter.

Let me know if this interests you! I am happy to submit a PR removing the 4 easiest dependencies. And to experiment with OpenAPI codegen. I think that would be about 1 full days work.

For this protobuf schema:

message MtuSizeRequest {
  string remote_id = 1;
  uint32 mtu = 2;
}

protobuf dart code:

// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: mtu_size_request.proto

import 'dart:core' show int, bool, double, String, List, override;
import 'package:protobuf/protobuf.dart';

class MtuSizeRequest extends GeneratedMessage {
  static final BuilderInfo _i = BuilderInfo('MtuSizeRequest')
    ..aOS(1, 'remoteId')
    ..a<core.int>(2, 'mtu', PbFieldType.OU3)
    ..hasRequiredFields = false;

  MtuSizeRequest() : super();
  MtuSizeRequest.fromBuffer(List<int> i,
      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
      : super.fromBuffer(i, r);
  MtuSizeRequest.fromJson(String i,
      [ExtensionRegistry r = ExtensionRegistry.EMPTY])
      : super.fromJson(i, r);
  MtuSizeRequest clone() => MtuSizeRequest()..mergeFromMessage(this);
  BuilderInfo get info_ => _i;
  static MtuSizeRequest create() => MtuSizeRequest();
  static PbList<MtuSizeRequest> createRepeated() =>
      PbList<MtuSizeRequest>();
  static MtuSizeRequest getDefault() {
    if (_defaultInstance == null) _defaultInstance = MtuSizeRequest._();
    return _defaultInstance;
  }

  static MtuSizeRequest _defaultInstance;
  static void $checkItem(MtuSizeRequest v) {
    if (v is! MtuSizeRequest) checkItemFailed(v, 'MtuSizeRequest');
  }

  String get remoteId => $_getS(0, '');
  set remoteId(String v) {
    $_setString(0, v);
  }

  bool hasRemoteId() => $_has(0);
  void clearRemoteId() => clearField(1);

  int get mtu => $_get(1, 0);
  set mtu(int v) {
    $_setUnsignedInt32(1, v);
  }

  bool hasMtu() => $_has(1);
  void clearMtu() => clearField(2);
}

OpenAPI schema:

components:
  schemas:
    MtuSizeRequest:
      type: object
      properties:
        remote_id:
          type: string
        mtu:
          type: integer
          format: uint32
      required:
        - remote_id
        - mtu

OpenAPI dart code:

import 'package:json_annotation/json_annotation.dart';

part 'mtu_size_request.g.dart';

@JsonSerializable()
class MtuSizeRequest {
  final String remote_id;
  final int mtu;

  MtuSizeRequest({required this.remote_id, required this.mtu});

  factory MtuSizeRequest.fromJson(Map<String, dynamic> json) =>
      _$MtuSizeRequestFromJson(json);

  Map<String, dynamic> toJson() => _$MtuSizeRequestToJson(this);
}

closing. these were removed.