The logic of the `function` is both reasonable and understandable. I think you have misunderstood how `.property(...)` works in Ember, though. What you've written is
```js
image: function() {
  // some logic
}.property('image')
```
What that says to Ember is *recompute the `LineItem`'s `image` property every time the `image` property changes*. That's redundant. In fact, it could even cause infinite loops if Ember weren't smart about they way it expires cached properties.

What you *mean* to express is *recompute the `LineItem`'s `image` property every time the `variant`'s `images` list changes*. That looks like
```js
image: function() {
  // some logic
}.property('variant.images.@each')
```
If `variant.images` is a plain `Array`, Ember can't observe the `@each` part (though it doesn't hurt to add it to the `image` definition) -- at least not without ES6's `Object.observe`. That is

 * `lineItem.set('variant', { images: [] })` recomputes `image`
 * `lineItem.set('variant.images', [] })` recomputes `image`
 * `lineItem.get('variant.images').unshift({ ... })` does *not* recompute `image`

If you wrap `variant.images` in an `Ember.ArrayProxy`, though, Ember will be able to observe not only changes to `variant` and the `variant.images` `Array` reference, but also the *content* of that `Array`.
```js
Variant = Em.Object.extend({
  coerceImages: function() {
    var images = Ember.makeArray(this.get('images')); // coerce to Array-like
    if (!(images instanceof Ember.ArrayProxy)) {
      // then coerce to ArrayProxy:
      images = Ember.ArrayProxy.create({ content: images });
    }
  }.on('init')
});
```