I don't think it's direct property access that's the problem, but rather, mutability.
 "There was no way to decorate such operations with cross-cutting concerns like logging or validation"
 "Direct access does not allow you to organize the functionality associated with getting and setting properties, it forces the code doing the getting and setting to also be responsible for anything else associated with getting and setting."
 "Whereas we can’t do anything like that with direct property access. Mediating property access with methods is more flexible than directly accessing properties, and this allows us to organize our program and distribute responsibility properly."
The point of this is to illustrate the difficulties of the other 99.9%. Including explaining why existing popular frameworks like Ember and libraries like Backbone do what they do.
The real question is: if our data has real validation and invariants, who maintains them?
- Does every piece of code that might change one attribute have to worry about it?
- Do individual objects protect themselves through methods and take responsibility?
- Or does a whole managed context take responsibility, allowing it to guarantee invariants about groups of objects together?
Experience tells us the first option quickly becomes problematic. The second certainly works, but requires discipline in how you design objects (the origin of many of the DDD patterns). The third is less widely used, seems to work better, but has some overhead. But don't kid yourself that it's less indirection/metaprogramming. It's more.
> we go through an even greater indirection, firing an abstract action and letting a store figure out how to make changes to the appropriate data
Can't this indirection just be modeled as a function? Instead of firing an action we call a function, which returns the appropriate state updates. No metaprogramming, and composable when used with cursor pattern to run the actual state update effect. (ActionStoreDispatcher flux doesn't compose)
(You probably know about this but others may not.) I like Elm's architecture, which has typed update functions that can be nested. This makes the full stack of the component composable and is something like a cursor: https://gist.github.com/evancz/2b2ba366cae1887fe621
One (officially blessed) example of a different model layer is combining React with something like Immutable.js, which does use setters which return new objects for each modification, allowing shallow comparisons of everything.
There are many, many, MANY things you can do when you make setting and retrieving a property "programmable." Injecting "method advice" to propagate changes--as the post describes--is one. Making data immutable through copy-on-write is another.
Same mechanism, entirely different architectural objectives.