Skip to content

Refactoring to remove late variables and cyclic dependencies #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Mar 25, 2024

Conversation

eliasyishak
Copy link
Contributor

@eliasyishak eliasyishak commented Mar 7, 2024

Related to:

Changes made in this PR:

  • Removed all late variables from AnalyticsImpl, ConfigHandler
  • All Initializer methods for creating files have been converted to static methods
  • LogHandler and UserProperty includes instance member errorSet to keep track of any errors encountered
    • Using this errorSet instance variable, we are able to delete error_handler.dart and handle the logic within AnalyticsImpl
  • Deleted session.dart and consolidated session logic into UserProperty

  • I’ve reviewed the contributor guide and applied the relevant portions to this PR.
Contribution guidelines:

Note that many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.

@@ -86,6 +85,8 @@ class Initializer {
sessionFile.createSync(recursive: true);
sessionFile
.writeAsStringSync('{"session_id": ${now.millisecondsSinceEpoch}}');
// TODO: eliasyishak, remove the below once https://github.com/google/file.dart/issues/236 is fixed
sessionFile.setLastModifiedSync(clock.now());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you doing this solely for test code? Let's try to avoid doing extra file system operations just for the sake of tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, a test consistently fails if we don't set the modified timestamp because it thinks there is more than one session since the last modified timestamp gets set to something like 2000-01-01 00:08:00.000

https://github.com/eliasyishak/tools/blob/remove-late-variables/pkgs/unified_analytics/test/unified_analytics_test.dart#L1089

I don't think deleting a valid test because of a bug would is ideal in this case either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this is not a bug, the dartdocs explicitly say that a fake clock is used for the MemoryFileSystem.test constructor. Currently trying to refactor around this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've moved the call to File.setLastModifiedSync into the test... where it should have probably been the whole time. Good catch :)

@eliasyishak eliasyishak marked this pull request as ready for review March 11, 2024 18:37
@eliasyishak eliasyishak changed the title [WIP] Refactoring to remove late variables and cyclic dependencies Refactoring to remove late variables and cyclic dependencies Mar 11, 2024
@@ -94,10 +91,17 @@ abstract class Analytics {
toolsMessageVersion: kToolsMessageVersion,
fs: fs,
gaClient: gaClient,
surveyHandler: SurveyHandler(homeDirectory: homeDirectory, fs: fs),
surveyHandler: SurveyHandler(
dismissedSurveyFile: fs.file(p.join(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this file path being constructed twice, here on line 95 and later on line 174, can we make it a shared static function on the SurveyHandler class that takes in the home path as an argument, that way if/when we change the path we only have to change one place? Or, if the path will always be the same relative to home, can we just pass in the home path to the constructor and have the constructor figure it out?

Copy link
Contributor Author

@eliasyishak eliasyishak Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually had this thought as well, except i wanted to do this for all of the file paths we use for the 5 files we generate.

I was thinking of making an Artifacts class with getters for each file, simple example below

import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:path/path.dart' as p;

class Artifacts {
  static File dismissedSurveyFile({
    required Directory homeDirectory,
    required FileSystem fs,
  }) =>
      fs.file(p.join(homeDirectory.path, 'path', 'to', 'dismissedSurvey.json'));

  static File logFile({
    required Directory homeDirectory,
    required FileSystem fs,
  }) =>
      fs.file(p.join(homeDirectory.path, 'path', 'to', 'analytics.log'));
}

void main() {
  final fs = MemoryFileSystem.test();
  final homeDirectory = fs.directory('home');

  homeDirectory.createSync();

  final dismissedSurveyFile =
      Artifacts.dismissedSurveyFile(homeDirectory: homeDirectory, fs: fs);
  dismissedSurveyFile.createSync(recursive: true);


  final logFile = Artifacts.logFile(homeDirectory: homeDirectory, fs: fs);
  logFile.createSync(recursive: true);
}

Thoughts?

Copy link
Contributor Author

@eliasyishak eliasyishak Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we could create an instance of Artifacts and pass the filesystem and homedirectory in the constructor so we could simply run something like the below

import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:path/path.dart' as p;

class Artifacts {
  final Directory homeDirectory;
  final FileSystem fs;

  Artifacts({required this.homeDirectory, required this.fs});

  File get dismissedSurveyFile =>
      fs.file(p.join(homeDirectory.path, 'path', 'to', 'dismissedSurvey.json'));

  File get logFile =>
      fs.file(p.join(homeDirectory.path, 'path', 'to', 'analytics.log'));
}

void main() {
  final fs = MemoryFileSystem.test();
  final homeDirectory = fs.directory('home');

  homeDirectory.createSync();

  // Create an instance that we can pass around
  final _artifacts = Artifacts(homeDirectory: homeDirectory, fs: fs);

  final dismissedSurveyFile = _artifacts.dismissedSurveyFile;
  dismissedSurveyFile.createSync(recursive: true);

  final logFile = _artifacts.logFile;
  logFile.createSync(recursive: true);
}

But either way, I was thinking of adding this in a separate PR

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think overall, I would try to avoid adding new classes unless you have a set of behaviors (functions) that:

  1. mutate state that they exclusively own; and/or
  2. you need to model a hierarchy of types (e.g. Animal, Dog, Cat)

Thus, I would prefer these just be top level functions

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you decide to keep the dependency on package:file (which I think is reasonable), these functions could simply take one argument, Directory homeDirectory, and then you could specify the path to the desired files via the FileSystemEntity.childDirectory and FileSystemEntity.childFile methods, which will ensure the appropriate path separator is used for the file system your home directory was created from.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this in a separate PR SGTM.

eliasyishak added a commit to eliasyishak/tools that referenced this pull request Mar 14, 2024
Copy link
Contributor

@christopherfujino christopherfujino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

eliasyishak added a commit that referenced this pull request Mar 14, 2024
* Rewrite the `last_ping` key again

* Apply test fix from #247

* Use timestamp instead of null

* Format fix

* Update version

* Code review comments

* Lingering comment
@eliasyishak eliasyishak merged commit 5e26782 into dart-lang:main Mar 25, 2024
@eliasyishak eliasyishak deleted the remove-late-variables branch March 25, 2024 16:39
@devoncarew
Copy link
Member

FYI that it looks like we'll need updates to the dart sdk repo (and google3?) in order to rev to the commit w/ this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants