I have an index page with a controller scoped to <body>
I'm finding it very convenient to store objects on the body controller that need to be accessed by multiple views.
My question is, is there anything wrong with doing this? Traditionally, I store such objects in a service, but sometimes I just have random things that i want to persist throughout the session and i'm finding the body controller fits them quite nice. Want to make sure I understand the best practice there, why i might not do that, or why it is actually a fine idea?
The Angular Documentation on Understanding Scopes, says the following:
Nesting controllers using ng-controller results in normal prototypal
inheritance, just like ng-include and ng-switch, so the same
techniques apply. However, "it is considered bad form for two
controllers to share information via $scope inheritance" --
http://onehungrymind.com/angularjs-sticky-notes-pt-1-architecture/ A
service should be used to share data between controllers instead.
I would argue that using a service is easier to test and it is separation of concerns. Also, depending on the number of variables and their names, it will become quite confusing to keep track of the right variables. If you use a service on the other hand, some IDEs (e.g. Webstorm) will be able access the variables with auto-completion.
I would say that in general this is a very bad practice because it goes against one of the golden principles of angularjs, which is to keep the structure and the behavior separated, we can do that thanks to the fact that dependency injection is at the core of angularjs architecture.
In general doing what you are suggesting will make your code to be more difficult to test and reuse, and in the long run more difficult to maintain too.
Related
I understand that we encapsulate data to prevent things from being accessed that don't need to be accessed by developers working with my code. However I only program as a hobby and do not release any of code to be used by other people. I still encapsulate, but it mostly just seems to me like I'm just doing it for the sake of good policy and building the habit. So, is there any reason to encapsulate data when I know I am the only one who will be using my code?
Encapsulation not only about hiding data.
It is also about hiding details of implementation.
When such details are hidden, that forces you to use defined class API and the class is only who can change it inside.
So just imagine a situation, when you opened all methods to any class interested in them and you have a function that performs some calculations. And you've just realized that you want to replace it because the logic is not right, or you want to perform some complicated calculations.
In such cases sometimes you have to change all the places across your application to change the result instead of changing it in only one place, in API, that you provided.
So don't make everything public, it leads to strong coupling and pain during update process.
Encapsulation is not only creating "getters" and "setters", but also exposing a sort of API to access the data (if needed).
Encapsulation lets you keep access to the data in one place and allow you to manage it in a more "abstract" way, reducing errors and making your code more maintainable.
If your personal projects are simple and small, you can do whatever you feel like in order to produce fast what you need, but bear in mind the consequences ;)
I don't think unnecessary data access can happen only by third party developers. It can happen by you as well right? When you allow direct access to data through access rights on variables/properties, whoever is working with that, be it you, or someone else may end up creating bugs by accessing data directly.
I have been working with Angular for some time now, and I fail to see how it is an improvement from my previous way of coding.
First, I can't see what's wrong with having a central object to hold your project. After all, the injector is a singleton that looks up your dependencies into a central place, so Angular does have a central object, it's just hidden. Namespacing doesn't necessarily mean coupling, if it's done properly. And even when it's done, you don't need every single object of your code to be loosely coupled with the others. Besides, anytime you create a standalone JS script, you have to wrap it into Angular to make them play nice together.
Second, it's very verbose to declare all your dependencies everytime (especially with minification), so there is no gain from the readability point of view compared to proper namespacing.
Third, the performance gain is minimal. It forces me to use singletons everywhere, but I can do that on my own if I need to, and most of the time, I don't (network and DOM manipulations are my bottleneck, not JS objects).
In the end, I like the "enhanced" HTML and the automatic two-way bindings, but I can't see how the injection makes it any better than the way other frameworks deal with dependencies, given that it doesn't even provide dynamic loading like require.js. I haven't see any use case where I say to myself "oh, this is where it's so much better than before, I see" while coding.
Could you explain to me what benefits this technical choice brings to a project?
I can see only one for now: convention and best practice enforcement. It's a big one to create a lib ecosystem, but for now I don't see the fruit of it in the Angular community.
For me there are few aspects of how Angular's dependency injection is improving my projects, which I will list here. I hope that this will show you how OTHERS can benefit from it, but if you are well organised and experienced JS developer, then perhaps it might not be the same case for you. I think at some point this is just the matter of developing your own tools and coding guide.
Unified, declarative dependency resolving
JS is dynamic language (that's new, huh?) which gives a lot of power and even more responsibility to the programmer. Components can interact with each other on various ways by passing around all sorts of objects: regular objects, singletons, functions, etc. They can even make use of blocks of code which were not even mentioned to be used by other components.
JS has never had (and most likely never will) a unified way of declaring public, private or package (module) scopes like other languages have (Java, C, C#). Of course there are ways of encapsulating logic, but ask any newcomer to the language and he will simply don't know how to use it.
What I like about DI (not only in Angular, but in general) is the fact that you can list dependencies to your component, and you are not troubled how this dependency got constructed. This is very important for me, especially that DI in Angular allows you to resolve both kinds of components: these from the framework itself (like $http), or custom ones (like my favorite eventBus which I'm using to wrap $on event handlers).
Very often I look at the declaration of a service and I know what it does and how it does it just by looking at dependencies!
If I was to construct and/or make use of all those objects deep in the component itself, then I would always have to analyze implementation thoroughly and check it from various aspects. If I see localStorage in dependencies list, I know for the fact that I'm using HTML5 local storage to save some data. I don't have to look for it in the code.
Lifespan of components
We don't need to bother anymore about order of initialization of certain components. If A is dependent on B then DI will make sure that B is ready when A needs it.
Unit testing
It helps a lot to mock out components when you are using DI. For instance, if you have controller: function Ctrl($scope, a, b, c, d) then you instantly know what it is dependent on. You inject proper mocks, and you are making sure that all parties talking and listening to your controller are isolated. If you have troubles writing tests then you most likely messed up levels of abstraction or are violating design principles (Law Of Diameter, Encapsulation, etc.)
Good habits
Yes, most likely you could use namespacing to properly manage the lifespan of your objects. Define singleton where its needed and make sure that noone messes up your private members.
But honestly, would you need that if the framework can do it for you?
I haven't been using JS "the right way" just until I learned Angular. It's not that I didn't care, I just didn't have to since I was using JS just for some tweeks of UI, primarly based on jquery.
Now its different, I got a nice framework which forces me a bit to keep up with good practices, but it also gives me great power to extend it and make use of the best features that JS has.
Of course poor programmers can still break even the best tool, but from what I've learned by recently reading "JS the good parts" by D. Crockford people were doing reeeeeealy nasty stuff with it. Thanks to great tools like jQuery, Angular and others we now have some nice tool which helps to write good JS applications and sticking to best practices while doing so.
Conclusion
As you have pointed out, you CAN write good JS applications by doing at least those three things:
Namespacing - this avoids adding stuff to global namespace, avoids potential conflicts and allows for resolving proper components easily where needed
Creating reusable components / modules - by, for instance, using function module pattern and explicitly declaring private and public members
Managing dependencies between components - by defining singletons, allowing for retrieving dependencies from some 'registry', disallowing of doing certain stuff when certain conditions are not meet
Angular simply does that by:
Having $injector which manages dependencies between components and retrieves them when needed
Forcing to use factory function which has both PRIVATE and PUBLIC APIs.
Let the components talk to each other either directly (by being dependent of one another) or by shared $scope chain.
I am building a CRUD application using angularjs. Currently, I am using the json models returned from the back-end directly in my controllers. These models have a 3-4 level deep hierarchy. So my controller code looks like
$scope.prop1 = object1.object2.object3
...
I am wondering whether I should decouple my controllers from these back-end models. So instead of using the model objects directly, create new (flattened) models and then use them in the controller. Is that a recommended practice?
What are the advantages / disadvantages of this ?
My advice would be to check domain of the object you're passing from backend. Do object1 really contain object2? Are those objects connected or it is just handy to return?
Speaking about AngularJS - there is no any difference. You can $watch('object1.object2.object3') with mostly same performance impact as $watch('object3'). There will be no any error if object2 will not contain object3. There will be a very small difference, as $parse will parse your expression to AST, and evaluating it will take little bit longer to traverse to third object. But this difference would be so small, so it would be extremely hard to notice.
So I would advice not to "flatten" everything or "normalise" into strict hierarchy, but try to figure our real relations between objects. Even if on start you won't see any difference, later it will pay back you with much higher maintainability rate.
I have been thinking about this lately. Up until now I have always subscribed to John Papa's recommendation which can be seen here:
https://github.com/johnpapa/angular-styleguide#controllers
Define a controller for a view, and try not to reuse the controller for other views. Instead, move reusable logic to factories and keep the controller simple and focused on its view.
He gives a reason that I don't understand but for me it was primarily motivated by ease-of-work/maintainability. Basically, in working on large applications, it really sucks to come upon a bloated controller that is responsible for several disparate views. If a developer wants to clean up the controller, he/she has to go to each view and determine what is being used and why (so that methods can be consolidated if they are very similar) which is a big job. Typically (especially if they are under time constraints), they choose to just add whatever functionality they need to the model and to "come back to it later" which is how it got bloated in the first place. Also, I have always used the controller/directive as an indication of whether logic is repeated in many views or not (i.e. if another developer walks up to a controller that I have written he/she can be sure that I have only used it with one view because otherwise it would be directive).
This is a similar problem to the endpoint-problem which basically has people adding endpoints on an as-need basis and the eventually due to new people not knowing about old endpoints or simple forgetfulness the API gets super bloated and repetitive.
However, as I said, recently I have been thinking that this 1-1 controller to view relationship really works against the entire MVC pattern because it couples the model to the view and destroys the separation of concerns. I mean, as long as a controller stays focused (i.e. we have an EditUserCtrl whose job it is to edit a user etc.) then why shouldn't two views be able to use that controller? I mean if the business decides it needs a new view in another place that has the same function, why shouldn't I just write a new view and hook it up to the old controller? I guess what I am saying is that I am having trouble reconciling a convention that goes against the fundamentals of a framework.
Would love to hear others thoughts on this. Thanks in advance.
Like you said yourself. If a controller is responsible for more than one view, any developer can walk up to it, change something in the hopes of adding new functionality to view A and not even knowing it's breaking view B. I think the primarily goal would be to keep controllers clean and neat. That way, it's best to have 2 controllers almost identicals, but with only 2~3 line of codes than to have files being referenced by a numerous number of other files that nobody has control over it.
At one hand, you have to change 2 controllers if something drastically changes in view A and view B, but if it's a complex task, you'll probably have the controllers calling some sort of Gateway and that might mean that you won't have to change any of the controllers at all (good outcome).
On the other hand, if you have 10 different views repeating the same 2~3 lines of code, maybe it's time to abstract the controller functionality.
It doesn't couple the model because the it's best practice to have the business logic in services and view logic in directives , and have there be no real logic in the controllers. So you can one controller per view, but that controller should be very skinny. Personally, I like to only use controllers to assign and communicate variables between services and directives. If you want to reuse controller code, what's stopping you from either putting that logic in directives and services?
Almost none of the controllers I write (and for my job I write a large enterprise application in angular) have logic in them. Granted sometimes logic in controllers is unavoidable, but try to keep as little as possible there.
In this way, the controller stays focused. For a large application, with, say, 10 pages, it's better for both usability and readability to have small controllers for each page instead of one giant controller with a mix of variables, and when you want to re-use methods and functions, put them in services. If you find yourself having three pages with a form or button that has the exact same logic, then that might be better served with a custom directive.
I have been working with Angular for some time now, and I fail to see how it is an improvement from my previous way of coding.
First, I can't see what's wrong with having a central object to hold your project. After all, the injector is a singleton that looks up your dependencies into a central place, so Angular does have a central object, it's just hidden. Namespacing doesn't necessarily mean coupling, if it's done properly. And even when it's done, you don't need every single object of your code to be loosely coupled with the others. Besides, anytime you create a standalone JS script, you have to wrap it into Angular to make them play nice together.
Second, it's very verbose to declare all your dependencies everytime (especially with minification), so there is no gain from the readability point of view compared to proper namespacing.
Third, the performance gain is minimal. It forces me to use singletons everywhere, but I can do that on my own if I need to, and most of the time, I don't (network and DOM manipulations are my bottleneck, not JS objects).
In the end, I like the "enhanced" HTML and the automatic two-way bindings, but I can't see how the injection makes it any better than the way other frameworks deal with dependencies, given that it doesn't even provide dynamic loading like require.js. I haven't see any use case where I say to myself "oh, this is where it's so much better than before, I see" while coding.
Could you explain to me what benefits this technical choice brings to a project?
I can see only one for now: convention and best practice enforcement. It's a big one to create a lib ecosystem, but for now I don't see the fruit of it in the Angular community.
For me there are few aspects of how Angular's dependency injection is improving my projects, which I will list here. I hope that this will show you how OTHERS can benefit from it, but if you are well organised and experienced JS developer, then perhaps it might not be the same case for you. I think at some point this is just the matter of developing your own tools and coding guide.
Unified, declarative dependency resolving
JS is dynamic language (that's new, huh?) which gives a lot of power and even more responsibility to the programmer. Components can interact with each other on various ways by passing around all sorts of objects: regular objects, singletons, functions, etc. They can even make use of blocks of code which were not even mentioned to be used by other components.
JS has never had (and most likely never will) a unified way of declaring public, private or package (module) scopes like other languages have (Java, C, C#). Of course there are ways of encapsulating logic, but ask any newcomer to the language and he will simply don't know how to use it.
What I like about DI (not only in Angular, but in general) is the fact that you can list dependencies to your component, and you are not troubled how this dependency got constructed. This is very important for me, especially that DI in Angular allows you to resolve both kinds of components: these from the framework itself (like $http), or custom ones (like my favorite eventBus which I'm using to wrap $on event handlers).
Very often I look at the declaration of a service and I know what it does and how it does it just by looking at dependencies!
If I was to construct and/or make use of all those objects deep in the component itself, then I would always have to analyze implementation thoroughly and check it from various aspects. If I see localStorage in dependencies list, I know for the fact that I'm using HTML5 local storage to save some data. I don't have to look for it in the code.
Lifespan of components
We don't need to bother anymore about order of initialization of certain components. If A is dependent on B then DI will make sure that B is ready when A needs it.
Unit testing
It helps a lot to mock out components when you are using DI. For instance, if you have controller: function Ctrl($scope, a, b, c, d) then you instantly know what it is dependent on. You inject proper mocks, and you are making sure that all parties talking and listening to your controller are isolated. If you have troubles writing tests then you most likely messed up levels of abstraction or are violating design principles (Law Of Diameter, Encapsulation, etc.)
Good habits
Yes, most likely you could use namespacing to properly manage the lifespan of your objects. Define singleton where its needed and make sure that noone messes up your private members.
But honestly, would you need that if the framework can do it for you?
I haven't been using JS "the right way" just until I learned Angular. It's not that I didn't care, I just didn't have to since I was using JS just for some tweeks of UI, primarly based on jquery.
Now its different, I got a nice framework which forces me a bit to keep up with good practices, but it also gives me great power to extend it and make use of the best features that JS has.
Of course poor programmers can still break even the best tool, but from what I've learned by recently reading "JS the good parts" by D. Crockford people were doing reeeeeealy nasty stuff with it. Thanks to great tools like jQuery, Angular and others we now have some nice tool which helps to write good JS applications and sticking to best practices while doing so.
Conclusion
As you have pointed out, you CAN write good JS applications by doing at least those three things:
Namespacing - this avoids adding stuff to global namespace, avoids potential conflicts and allows for resolving proper components easily where needed
Creating reusable components / modules - by, for instance, using function module pattern and explicitly declaring private and public members
Managing dependencies between components - by defining singletons, allowing for retrieving dependencies from some 'registry', disallowing of doing certain stuff when certain conditions are not meet
Angular simply does that by:
Having $injector which manages dependencies between components and retrieves them when needed
Forcing to use factory function which has both PRIVATE and PUBLIC APIs.
Let the components talk to each other either directly (by being dependent of one another) or by shared $scope chain.