-
Notifications
You must be signed in to change notification settings - Fork 41
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not clear to me what global
is or means. Can you please explain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
src/CordovaLogger.js
Outdated
this.addLevel('results', 10000); | ||
|
||
this.setLevel('normal'); | ||
function formatError (error, isVerbose) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would definitely favor extracting it into a module in the utils
folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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()
&global
to turnCordovaLogger
into a singleton ES5 object class according to https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ - Refactor
CordovaLogger
into 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):
- brody4hire@fe58df2 - Use const at the beginning of
src/CordovaLogger.js
- brody4hire@36f2309 - Turn
CordovaLogger
into a singleton ES5 object class (keeping it as an ES5 class function), usingSymbol.for()
&global
instead of a pseudo-singleton var as described in https://derickbailey.com/2016/03/09/creating-a-true-singleton-in-node-js-with-es6-symbols/ - brody4hire@8981e37 - Refactor
CordovaLogger
into an ES6 class, with static get attribute methods (static attributes) after the constructor to make it easier to understand the changes usinggit show -b
(andformatError
function left in place) - brody4hire@34ae645 - put static attributes before
CordovaLogger
constructor
(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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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...