Thoughts on reusing a controller for different routes - ember.js

I have several objects which are behaving very similarly. I would like to provide a base implementation for the controllers related to those objects, and then extend those controllers to slightly customize the behaviour. I am doing something like this:
App.BaseIndexController = Ember.ArrayController.extend({
...
});
And now I would use the base controller to define my real object controller:
App.AgentsIndexController = App.BaseIndexController.extend({
....
});
I have two questions:
Are there any general comments discouraging this kind of reuse?
Is the extend mechanism the right way to reuse a generic controller implementation, ensuring that no state data will "leak" between controllers extending the same base controller?

You can do it as you've suggested, but note that any properties defined in App.BaseIndexController will leak over if they've been initiated (check this out for a common mistake)
Mixins can also work well, since they're more reusable. Ember uses Mixins a lot internally so you can't go wrong with that approach.

Related

Should I always include this._super(...arguments) when overwriting an Ember member function

In Ember.js, there are a lot of functions that require you to call this._Super(...arguments) before calling them. A quick example from the documentation:
import Component from '#ember/component';
export default Component.extend({
didRender() {
this._super(...arguments);
console.log('I rendered!');
}
});
Are there ever cases in Ember where we do not need to call this._super()? The reason I ask is because often times, I will write some hooks for either my controllers or routes where I simply forget to call this._super(...arguments) and, as far as I can tell, everything works the same.
Should I always include a super() method before overwriting any member function in Ember?
Yes, you better include this._super, although it is not "a must" in most cases.
There is only one place I know where this is critical - init. Most probably constructor too, as mentioned above, but I never needed to overwrite a constructor. However, consider this:
As many people mentioned, something might be changed in future versions and including this._super may help to avoid bugs
If you use mixin from some ember addon, they might also overwrite ember methods or do it in future versions
Let's say you are extending component from your own mixin and right now your mixin does not overwrite didRender. But what if you will need to change that in future?
So, while in most cases including this._super is not critical, it is good to include it anyway. Except cases when you intended to completely overwrite default behavior.
Yes. In a long lost thread someone once told me that the behavior of the overridden method was not necessarily guaranteed by semver so I should always call super to avoid strangeness in the future if something was added to an upstream method that is currently doing nothing.
Yes you should always do so. If you don't, ember won't execute the code that handles behind the scenes stuff which will result in weird behaviour you might not be able to debug..
P.S : As an experiment just try overriding a setupController method in any route in your app without calling this._super(...arguments) and see what happens.

Best practices with Ember ArrayProxy

Ember's Em.ArrayProxy and Em.Array have many programatic methods available for notifying observers of changes to content. For example:
arrayContentDidChange
arrayContentWillChange
enumerableContentDidChange
enumerableContentWillChange
contentArrayWillChange
Em.ArrayProxy also has several methods for manipulating the ArrayProxy's content. For example:
this.pushObject('something random');
// Or
this.insertAt(2, 'something random');
When using the latter methods, does one have to use them in conjunction with the former methods? It seems silly that Ember's usually-automated property observers would require a manual kick here but I don't find the documentation very clear.
No, you don't have to use any methods in conjunction.
If you want to add items to your ArrayProxy, simply pushObject(). You would know this by just using the method and seeing that it just works.
From the docs:
This mixin implements Observer-friendly Array-like behavior. It is not a concrete implementation, but it can be used up by other classes that want to appear like arrays.
http://emberjs.com/api/classes/Ember.Array.html
Ember.Array is a type of class that in other programming languages (without mixins) receives the name of an interface.
An ArrayProxy wraps any other object that implements Ember.Array
http://emberjs.com/api/classes/Ember.ArrayProxy.html
Ember.ArrayProxy is exactly what the name says, a proxy, that wraps around any object that has implemented the Ember.Array interface.
The other methods, that you mention, might be implemented/overridden if you are making your own "subclass" of Ember.Array. Some must be implement to make your subclass ArrayProxy friendly. Or if you want to add custom behaviour, maybe write to a log whenever arrayContentDidChange, then you override that method and add whatever logic your app needs.
That is Object Oriented Programming and all those explanations are out of scope for the documentation of any framework.
Are you asking whether pushObject et cetera trigger those events?
From the documentation for insertAt:
This will use the primitive replace() method to insert an object at the specified index.
From the documentation for replace:
You should also call this.enumerableContentDidChange()
So, yes, a properly implemented ArrayProxy will trigger those events when you add or remove things.

Controller Properties extended from base class persist

I’m a little confused about something in Ember with the object model, specifically relating to controllers. I have a base class with a property that is an array and I’m extending two controllers from the base class. The array on the base class seems to persist across both instances of the base class; although, I thought Ember would make them two separate instances of the class. Crude example: http://emberjs.jsbin.com/firovahoxera/1/
Shouldn’t the base class instantiate as two different instances or am I thinking about this wrong? Thanks in advance.
Array's are objects in the sense that adding it to the controller adds a reference to that array to all instances of the controller.
If you want an instance on all of your controllers you can create the array on init.
App.BaseClassController = Ember.Controller.extend({
setupPersists: function(){
this.set('persists', []);
}.on('init')
});
http://jsbin.com/firovahoxera/2/edit

How to inject an abstract factory into an entity's method?

I have an Order entity with a refund() method that uses an abstract factory refundStrategyFactory to create the appropriate refund strategy at run-time:
public class Order extends Entity{
public void refund(Employee emp, Quantity qty, IRefundStrategyFactory refundStartegyFactory){
//use the abstract factory to determine the appropriate strategy at run-time.
}
}
I'm trying to use dependency injection and have IRefundStrategyFactory injected automatically into the refund() method, but I couldn't find a way to achieve this.
I'm not using the constructor injection because Order is an entity and we shouldn't inject services into entities unless it's going to be used temporarily as in the refund method. This is better explained by Misko Hevery's blog post To “new” or not to “new”…:
It is OK for Newable to know about Injectable. What is not OK is for
the Newable to have a field reference to Injectable.
A similar answer by Mark Seemann to a related question also advocates the same idea.
Bonus point, Aren't I exposing the internals of the refund() method by exposing its dependency on IRefundStrategyFactory? Should I sacrifice unit testing in isolation and create the factory inside the method itself?
Well ideally your domain model should be free infrastructure concerns and IOC is a infrastructure concern, it is recommended that the domain model be simple POJO's. So I would not inject beans into my domain model.
In this case i think you should have a application service which gets injected the factory class and it then just passes the factory class as a parameter to your Order class.
Does the factory class use some information from the Order class to decide which kind of strategy class to instantiate ?
Bonus point, Aren't I exposing the internals of the refund() method by
exposing its dependency on IRefundStrategyFactory?
I am not sure if there is such a thing as exposing the internals of a method, This concept fits more naturally with "exposing internals of a class", A method does some action and to do so it might need some information from the outside world, we could debate on how to pass in that information and whether that one method is doing too much or not ? ... But i cannot reason on whether a method "exposes its implementation", maybe you should elaborate on what you meant by that point
I'd solve this by starting a refund process with eventual consistency, where you trigger a Refund action. The listeners to this action and it's events would then do their own tasks, i.e. refund the cost of the goods, restock the items, etc. Alternatively you could just do this atomically in an application service that triggers several domain services, one after another, passing in the Order item:
FinancialService.RefundOrderGoods(myOrder);
StockService.RestockOrderItems(myOrder);
...
I'd avoid adding any services or repositories into your entities.
Your main problem is that you can't "injected automatically into the refund() method", but IMO that isn't a problem at all, since you can simply pass on the dependency onto the method but still use constructor injection in the service that calls this method:
public class ApplyRefundHandler : ICommandHandler<ApplyRefund>
{
private readonly IRefundStrategyFactory refundStartegyFactory;
private readonly IRepository<Order> orderRepository;
private readonly IRepository<Employee> employeeRepository;
public ApplyRefundHandler(IRefundStrategyFactory refundStartegyFactory,
IRepository<Order> orderRepository,
IRepository<Employee> employeeRepository)
{
this.refundStartegyFactory = refundStartegyFactory;
this.orderRepository = orderRepository;
this.employeeRepository = employeeRepository;
}
public void Handle(ApplyRefund command)
{
Order order = this.orderRepository.GetById(command.OrderId);
Employee employee = this.employeeRepository.GetById(command.EmployeeId);
order.refund(employee, command.Quantity, this.refundStartegyFactory);
}
}
Aren't I exposing the internals of the refund() method by exposing its
dependency on IRefundStrategyFactory? Should I sacrifice unit testing
in isolation and create the factory inside the method itself?
Yes you are, but in the same time you are probably violating the Single Responsibility Principle by adding a lot of business logic in the Order class. If you hide the abstractions, it means you need to inject them into the constructor and you will probably find out quickly that your Order class gets a lot of dependencies. So instead you can view the Order's methods as a Single Responsibility (a class in disguise) that has little to no relationships with the other methods in that class, and in that case it makes sense to pass in its dependencies into that method.
As a side node, please be aware that factory abstractions, like your IRefundStrategyFactory are usually not good abstractions. You should consider removing it, as described in detail here.

Why don't the arguments to create() behave more like setProperties()?

Something I find very counter-intuitive about Ember is you can overwrite a computed property setter functions ( http://emberjs.com/#toc_computed-properties-setters ) with the arguments to create(). See http://jsfiddle.net/zJQJw/2/
I found the best workaround for this is to call create().setProperties(properties) instead of create(properties), but this seems like an unnecessary gotcha to me. I realize it might break some apps at this point, but would you consider making create() behave more like setProperties()?
My motivation for asking for this is that init() will be called before setProperties() when using the create().setProperties(properties) pattern. This hasn't been a big problem yet, but I can see this being undesirable in some situations. This is a completely contrived example, but maybe you can see what I am getting at? http://jsfiddle.net/QJ8vX/2/
The only reason I can see for maintaining the current behavior is to do instance-specific overrides of setter methods. But in those cases you could just as easily do MyClass.extend({ overridenMethod: ... }).create(properties)
Would a change like this be considered for Ember 1.0? Or do I just have the wrong idea about how Ember's object model should work?
The main reason why we've pushed back on this change is that it makes it impossible to override properties that are defined on base classes as computed properties. For example, in Ember.View, the template property is a computed property:
template: Ember.computed(function(key, value) {
if (value !== undefined) { return value; }
var templateName = get(this, 'templateName'),
template = this.templateForName(templateName, 'template');
return template || get(this, 'defaultTemplate');
}).property('templateName').cacheable(),
When creating a subclass of Ember.View, you may want to override this definition with an explicit template function:
Ember.View.create({ template: Ember.Handlebars.compile('...') });
If the computed property doesn't handle the setter case, this attempt to override the computed property would be a silent failure.
If we made this change, it also introduces other questions about whether observers should trigger for properties passed into the create method. Both are possible to implement, and there are strong arguments for both approaches.
In the run-up to 1.0, it seems reasonable to consider an approach that would:
change create to use setProperties semantics
add a new API (override or createWithOverride) that would retain the existing semantics, in case you explicitly wanted to override existing computed properties
suppress observers for properties set due to create (or decide not to)
find a way to detect and warn about attempts to use the create API with computed properties that do not implement setters.
I would need to discuss it more, and consider the implications to existing apps, but it is definitely something worth considering, as it is definitely a pretty big gotcha for new developers. The fact that we needed to change the behavior for ember-data is a pretty good clue that something isn't quite right.
It's may be a dirty hack, but it's works for me.
Em.Object.reopenClass({
create: function(config) {
return this._super().setProperties(config);
}
});