Refactor CordovaLogger to singleton class#53
Conversation
Codecov Report
@@ Coverage Diff @@
## master #53 +/- ##
==========================================
+ Coverage 88.85% 88.88% +0.03%
==========================================
Files 19 20 +1
Lines 1795 1800 +5
Branches 368 368
==========================================
+ Hits 1595 1600 +5
Misses 200 200
Continue to review full report at Codecov.
|
| * @returns {CordovaLogger} Logger instance | ||
| */ | ||
| static get () { | ||
| if (Object.getOwnPropertySymbols(global).indexOf(INSTANCE_KEY) === -1) { |
There was a problem hiding this comment.
It is not clear to me what global is or means. Can you please explain?
There was a problem hiding this comment.
It's the global object. In a web browser, it would be window:
https://nodejs.org/dist/latest-v10.x/docs/api/globals.html#globals_global
There was a problem hiding this comment.
Got it. I would really appreciate pointers for some newer features such as global object & Symbol in the source or maybe in the commit message.
There was a problem hiding this comment.
global is a NodeJS specific thing, which I think has existed since the very early days.
Symbol is a built-in JS (ES6) language feature, which has been around for several years now.
I don't really think we should have comments everywhere providing an introduction to built-in language features, but I think it is probably valuable to have a link to https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ somewhere to explain the singleton design pattern we're implementing. I'll amend the commit with that added.
There was a problem hiding this comment.
link to https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/
the link explains it all
I guess it should be good enough to put it in the commit message; personally I would have put it in the source code for the sake of absolute clarity.
| this.addLevel('results', 10000); | ||
|
|
||
| this.setLevel('normal'); | ||
| function formatError (error, isVerbose) { |
There was a problem hiding this comment.
I am not so happy that the internal formatError utility function was moved for multiple reasons:
- makes it much harder to understand what changed in the diff
- I think higher-level API items belong up top and internal utility functions belong toward the end of the module.
There was a problem hiding this comment.
Yeah, that's a valid concern.
Personally I always find it non-obvious when functions are used in code before they are defined in the source. I know that's how JavaScript hoisting works, but I find it adds a bunch of mental overhead of keeping track of what's required from node modules and what's defined in the file but below where it's used.
There was a problem hiding this comment.
Argh
While I would not really accept that argument I don't think I can dismiss it as completely invalid.
What if we would factor formatError into an internal utility module?
Or look for an existing npm module that can do at least part of the job for us?
A crazy idea could be to turn formatError into a member function, don't think ES6 class explicitly supports private methods though.
There was a problem hiding this comment.
I thought about turning it into a member function. You're right that it wouldn't really be private, but if we made it a utility then it wouldn't really be private either.
I don't have a strong preference for either option, and we already have a utils folder, so maybe extracting it to there is the best option?
There was a problem hiding this comment.
I would definitely favor extracting it into a module in the utils folder.
There was a problem hiding this comment.
Sorry this review has taken so long.
On the plus side I am very happy with the changes on a functional level.
My understanding is that there are 2 major parts of the change:
- Use
Symbol.for()&globalto turnCordovaLoggerinto a singleton ES5 object class according to https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ - Refactor
CordovaLoggerinto an ES6 class
The bad part is that I find the actual changes pretty hard to follow, even if I do git show -b to ignore indentation changes.
In order to better understand the flow of the changes I made a logger-instance-in-smaller-commits branch on my fork that makes all of the changes except for moving formatError in smaller steps (with npm test succeeding on each of the commits):
- brody2consult@fe58df2 - Use const at the beginning of
src/CordovaLogger.js - brody2consult@36f2309 - Turn
CordovaLoggerinto a singleton ES5 object class (keeping it as an ES5 class function), usingSymbol.for()&globalinstead of a pseudo-singleton var as described in https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ - brody2consult@8981e37 - Refactor
CordovaLoggerinto an ES6 class, with static get attribute methods (static attributes) after the constructor to make it easier to understand the changes usinggit show -b(andformatErrorfunction left in place) - brody2consult@34ae645 - put static attributes before
CordovaLoggerconstructor
(Disregard my @brodybits TBD ??? comment, thanks for explaining on GitHub.)
I will understand if the smaller commits that I proposed are not desired, would like the changes to be easier to understand somehow.
I would also appreciate some kind of resolution for the code comments I raised.
42003fc to
b854657
Compare
|
@brodybits Updated with the requested changes |
brody2consult
left a comment
There was a problem hiding this comment.
Much better with the separate module and comment with a link to the singleton instance pattern. I have a couple questions that remain:
- Why make the functional singleton instance change and refactor to an ES6 class at the same time?
- I forgot to ask yesterday: what is the motivation to refactor to an ES6 class in the first place?
I am still not a big fan of ES6 classes and just sent my opinion to dev@cordova.apache.org for discussion. I wish I would have thought of this before you started the work.
brody2consult
left a comment
There was a problem hiding this comment.
Let's get this one merged. Much better than what we had before.
I continue to think we should be able to accomplish the same thing with 1-2 object factory functions and would like to give it a try someday.
I think we have to at least increase the minor release version, maybe the major release version.
I don't think this actually requires anything more than a patch release, since the exposed API hasn't changed. One thing to note is that we will have to make a similar change to CordovaEvents (unrelated to the change here, but needed for the same reason) and that one might need to be a breaking change |
What does this PR do?
Based on the discussion at apache/cordova-lib#721, this attempts to make CordovaLogger a proper singleton, such that we cannot end up with multiple instances of the logger even when multiple versions of cordova-common are in us (of course, that only applies if all those multiple versions are using this singleton pattern)
What testing has been done on this change?
All existing CordovaLogger tests pass locally.
It would be great to do a test with multiple instances to prove that this singleton pattern works, but I'm not even sure how we'd start setting up a test like that...