This question has less to do with how to do something, but more about best practices and what do others do?
I have a few services where I am using some kind of an external API (in this case the session storage api in the browser), where I am reusing the same constant string, the name of the company and the application, let's call it "ACME.Storage.", and this I want to prepend at the start of every "key" string. I see my options as:
I can just reuse the string "ACME.Storage." in every call.
I can create a JavaScript function where I create a new storage object that is configured with "ACME.Storage." once. That way, "ACME.Storage." appears once in my code.
I can create a local variable ans store "ACME.Storage." in it, then reuse that. Again, the string literal appears only once in my code.
I can create a separate javascript object that I can share.
I can use an AngularJS "constant"
I can add as a field to the app of config file.
I can store it somewhere where localized literal strings (even though this particular string isn't localized) and get it through a translation service.
I'm leaning toward using the "constant" service 'cause it's the one that's easily injectable. My only concern is that it's less encapsulated than some of the other options.
Opinions on the best practice?
To expand upon what Whishler posted, you can (and probably should) use the Constant module that Angular provides. Complete docs are found here: http://docs.angularjs.org/api/ng/type/angular.Module. Services are a common place for constants, but the Constant modules get applied before other provide methods. Another option would be Value, but it does pretty much the same thing.
Generally, I put constants into a service.
Depending what I'm doing, I may create a service that does nothing but store related constants. Or I may add them to another service representing a 'model'.
I'll also add that JavaScript doesn't officially have constants; so unless you wrote some code--such as your own accessors--you're just dealing with a variable that could be changed during the execution.
Related
TL;DR: Is it bad practice to use a global variable to prevent code executing unnecessarily, and if so what are the alternatives?
I have an Electron application that reads a stream of real time data from another application and outputs some elements of it on screen.
There are two types of data received, real time (telemetry) data of what is currently going on and more static data that updated every few seconds (sessionInfo).
The first time a sessionInfo packet is received I need to position and size some of the UI elements according to some of the data in it. This data will definitely not change during the course of the application being used, so I do not want the calculations based on it to be executed more than once*.
I need to listen for all sessionInfo packets, there are other things I do with them when received, it is just this specific part of the data that only needs to be considered once.
Given the above, is this a scenario where it would be appropriate to use a global variable to store this information (or even just a flag to say that this info had been processed) and use this to prevent the code executing multiple times? All my reading suggests that Global Variables are never a good idea, but short of allowing this code to execute repeatedly I am unsure what alternatives I have here.
*I recognise that allowing this would probably make no practical difference to my application, but this is a learning experience for me as well as producing something useful so I would like to understand the 'right' approach rather than just bodge something inefficient together and make it work.
Global variables are generally a bad practice for many reasons like:
They pollute the global scope, so if you create a global i, you
can't use that name anywhere else.
They make it impossible or very difficult to unit test your code.
You usually end up needing more of them than you think, to the point where many things become global.
A better practice is to create singleton services. For example, you might create a SessionService class that handles all your auth stuff. Or, perhaps a DataStreamService that holds the state variables of your data stream. To access that singleton, you'd import it into whatever file needs it. Some frameworks go even farther and have a single global data store, like react/redux.
Following a rapid-prototyping approach, I am developing an application in Marionette.js/backbone.js and heavily used the window-object to bind collections and views to the global stack (e.g. window.app.data, window.app.views).
Of course, it is always better (smoother!) to encapsulate objects in a single class and pass them as parameters where needed. However, this has some limitations when an app and its potential use-cases become really big. And as the data I deal with comes from an API and therefore would be anyway accessible to anybody interested, does that justify storing data in the window-object? Or are there other best-practices in ES6 (or especially Marionette.js) to achieve the same results, but in a more private manner?!
I already go into details about a simple namespacing pattern in JavaScript in another answer. You seem to be already close to this with window.app.data etc.
But it looks like you have a lot of misconceptions about how JavaScript works.
a namespace-based solution that integrates nicely with Browserify/AMD-modules
Then why not use RequireJS? Browserify? or Webpack? There's nothing that a global ridden spaghetti code can do that a modular approach can't do better.
such would be read-only
No. While not impossible to set an object property to read-only, you must explicitly do it with something like Object.seal or Object.freeze.
I do not want to attach objects to the namespace, but actual instances
JavaScript do not have "namespaces" as part of the language, it's just a pattern to scope all your code within literal objects (key-value).
You can put whatever you'd like.
const MyNamespace = {
MyType: Backbone.Model.extend({ /*...*/ }),
instance: new Backbone.Model(),
anyValue: "some important string",
};
Ideally, you would define the namespace within an IIFE to avoid leaking any variable to the global scope.
const app = app || {};
app.MyModel = (function(app){
return Backbone.Model.extend({
// ...
});
})(app);
[...] data I deal with comes from an API and therefore would be anyway accessible to anybody interested
Even if the data is contained within a module that do not leak to the global scope, anybody can access the data. That's how JavaScript works, it's in the user's browser, he can do whatever he wants with the code and the data.
does that justify storing data in the window-object?
No.
Or are there other best-practices in ES6
ES6 has nothing to do with the architecture and patterns you take for your app.
but in a more private manner?!
Like I said earlier, privacy in JavaScript can't be expected.
[encapsulate objects in a single class and pass them as parameters where needed] has some limitations when an app and its potential use-cases become really big.
That's just incorrect. It's the other way around. Software patterns exist solely to help alleviate any limitations that arise as a project grows in scope.
There are multiple patterns you can use that will help deal with the complexity of a bigger app, like:
Modular approach with components
Dependency injection
Service containers
Factories
Events
etc.
I didn't read specifically this book, but JavaScript Design Patterns seems to be a good way to learn more and it demonstrates specific implementations of software patterns in JS.
I am working on a project where in there are almost 90+ modules.
All modules has a set of input fields and on submit the data should be saved on the server.
At any given point in time only one module is active. But there can be open modules in the background.
Submit button is common to all modules, meaning there is only one Submit button throughout the application.
Below picture explains it more.
The prime motto is to keep the individual module changes to minimum and a way to handle certain things(validation, reload etc) in the module from a central place.
The current approach I am planning is,
Use a 'moduleInit' directive that all module should include in its
partial.
The directive takes the $scope of the module and pass it to a
common service/factory (pushConfigService)
The pushConfigService stores and keep this scope as long as the
module is open. Once the scope is destroyed the reference of the
same will be removed from the pushConfigService.
The footer panel is another directive with Submit button in it and
calls a save function in the pushConfigService which in turn calls
a $scope function in the module to get the form data.
pushConfigService talks to a bunch of other services like
dirtyChecker, apiGenerator and finally post data to the server.
Each module will have a set of scope methods defined with some standard names. Eg: _submit, _onSubmit, _cancel, _reload etc.
Another way to handle this, broadcast the submit event and each module listens to the same. There is possibility more actions will be added to the footer panel.
So I am little bit hesitant to use the broadcast approach.
My question, Is it a good idea to pass controller scope to a service? Any alternate suggestions?
Thanks in advance.
I believe your core concept is a nice way to handle this setup. Yet I'd suggest to split business logic from UI. I don't have a sample of your code so it is a little hard to build an exact example. Yet since you're using the $scope variable I'm going to assume you're not using a styleguide like or similar to John Papa's. His ways encourage you to not use the $scope and to stay close to actual JavaScript "classes".
How does this make a difference?
Instead of passing the whole scope, you'd be able to just pass the instance of your specific module. For one it is less confusing to you and colleagues to have a concrete interface to operate on instead of having to figure out the composition of given scope. In addition it prevents services from being able to alter the $scope.
The latter could be considered a good practice. Having just the controllers alter the scope make it easy to find the code which alters and manages the UI. From there on the controller could access services to do the actual logic.
Taking it one step further
So passing the class instance instead of scope should be an easy adjustment to the already proposed setup. But please consider the following setup as well.
It seems there are quite some different ways to handle and process the data provided by the module/end user. This logic is now implemented in the controller. One might think some of these modules share similar handling methods (big assumption there). You could move this logic to, so to speak, saving strategies, in services. On activation of a module, this module will set its preferred saving strategy in the service which handles the submit button click. Or more precisely, the save data method which should be called from the onClick handler in the controller.
Now these services/strategies might be shared among controllers, potentially setting up for a better workflow and less duplicated code.
Are there some benefits of using the methods defined on the localStorage object versus accessing the object properties directly? For example, instead of:
var x = localStorage.getItem(key);
localStorage.setItem(key, data);
I have been doing this:
var x = localStorage[key];
localStorage[key] = data;
Is there anything wrong with this?
Not really, they are, basically, exactly the same. One uses encapsulation (getter/setter) to better protect the data and for simple usage. You're supposed to use this style (for security).
The other allows for better usage when names(keys) are unknown and for arrays and loops. Use .key() and .length to iterate through your storage items without knowing their actual key names.
I found this to be a great resource : http://diveintohtml5.info/storage.html
This question might provide more insight as well to some: HTML5 localStorage key order
Addendum:
Clearly there has been some confusion about encapsulation. Check out this quick Wikipedia. But seriously, I would hope users of this site know how to google.
Moving on, encapsulation is the idea that you are making little in and out portals for communication with another system. Say you are making an API package for others to use. Say you have an array of information in that API system that gets updated by user input. You could make users of your API directly put that information in the array... using the array[key] method. OR you could use encapsulation. Take the code that adds it to the array and wrap it in a function (say, a setArray() or setWhateverMakesSense() function) that the user of your API calls to add this type of information. Then, in this set function you can check the data for issues, you can add it to the array in the correct way, in case you need it pushed or shifted onto the array in a certain way...etc. you control how the input from the user gets into the actual program. So, by itself it does not add security, but allows for security to be written by you, the author of the API. This also allows for better versioning/updating as users of your API will not have to rewrite code if you decide to make internal changes. But this is inherent to good OOP anyhow. Basically, in Javascript, any function you write is a part of your API. People are often the author of an API and it's sole user. In this case, the question of whether or not to use the encapsulation functions is moot. Just do what you like best. Because only you will be using it.
(Therefore, in response to Natix's comment below...)
In the case here of JavaScript and the localStorage object, they have already written this API, they are the author, and we are its users. If the JavaScript authors decide to change how localStorage works, then it will be much less likely for you to have to rewrite your code if you used the encapsulation methods. But we all know its highly unlikely that this level of change will ever happen, at least not any time soon. And since the authors didn't have any inherent different safety checks to make here, then, currently, both these ways of using localStorage are essentially the same. Except when you try to get data that doesn't exist. The encapsulated getItem function will return null (instead of undefined). That is one reason that encapsulation is suggested to be used; for more predictable/uniform/safer/easier code. And using null also matches other languages. They don't like us using undefined, in general. Not that it actually matters anyhow, assuming your code is good it's all essentially the same. People tend to ignore many of the "suggestions" in JavaScript, lol! Anyhow, encapsulation (in JavaScript) is basically just a shim. However, if we want to do our own custom security/safety checks then we can easily either: write a second encapsulation around the localStorage encapsulate, or just overwrite/replace the existing encapsulation (shim) itself around localStorage. Because JavaScript is just that awesome.
PT
I think they are exactly the same, the only thing the documenation states is:
Note: Although the values can be set and read using the standard
JavaScript property access method, using the getItem and setItem
methods is recommended.
If using the full shim, however, it states that:
The use of methods localStorage.yourKey = yourValue; and delete
localStorage.yourKey; to set or delete a key is not a secure way with
this code.
and the limited shim:
The use of method localStorage.yourKey in order to get, set or delete
a key is not permitted with this code.
One of the biggest benefits I see is that I don't have to check if a value is undefined or not before I JSON.parse() it, since getItem() returns NULL as opposed to undefined.
As long as you don't use the "dot notation" like window.localStorage.key you are probably OK, as it is not available in Windows Phone 7. I haven't tested with brackets (your second example). Personally I always use the set and get functions (your first example).
Well, there is actually a difference, when there is no local storage available for an item:
localStorage.item returns undefined
localStorage.getItem('item') returns null
One popular use case may be when using JSON.parse() of the return value: the parsing fails for undefined, while it works for null
I'm trying to serialize my business objects into JSON for consumption by a Javascript application. The problem is is that I'm trying to keep my business objects "pure" in the sense they are not aware of data access or persistence. It seems to me that "diluting" my objects with a toJSON() function would go against this goal. On the other hand, using an external object to serialize my business objects would not work since I keep all my instance variables private.
Am I approaching this totally the wrong way?
If the instance variables are private, they should not appear in a serialization that is being sent to a JavaScript application. By definition, if you're serializing them and sending them to a separate application, they are public. So, an external object should have some way of accessing them, probably through some sort of getter methods.
What purpose does searializing the data in JSON serve? Is it purely for reporting? If so, then Brian is correct, those variables should have getter methods.
If the purpose of serialization is to transport the data to a JavaScript app where it can be manipulated and then returned to the originating application, then perhaps you would be best served by creating a related class that serves the purpose of serialization while still maintaining strong encapsulation.
For example, in Java you could define an inner class. An inner class instance has direct access to all fields of the enclosing class instance without the need of getter methods. Or you could group with a package (or namespace) using the correct access modifiers to permit access by the serializer, but not by any other class.
Or you could use reflection. Or hijack the toString method. (Or shine it all and create a toJson method.)
Are you thinking of generating JSON from non-javascript code (like server-side Java)? The answer kind of depends on that: handling of JSON is quite different on Javascript and, say, Java. There's already an answer wrt javascript-side, which seems correct.
If this is on Java, there are libraries that can help; for example (Jackson) can deserialize any bean, using regular getX/setX method introspection; plus additional (and optional) annotations.