4 ms·
I think the uniform access principle is misguided (or at least misconstrued). It's a bad idea... in general. If you're building an API and you have need some
by emn13 13y ago
I think the uniform access principle is misguided (or at least misconstrued). It's a bad idea... in general. If you're building an API and you have need some kind of stable, unchanging interface to expose - then it makes sense.
But people are using it everywhere in their programs; and it's not really valid there. First of all, data-access is fast and computed functions may be slow. Hiding this difference means that writing efficient code becomes more tiresome - you need to consider each and every access as potentially expensive, even though the majority are probably trivial. This means you need to know the code better to get anywhere. And if you make it hard to write efficient code, people won't bother (and rightly so, since that's usually premature optimization).
Secondly, in most languages, simple data access is side-effect free and (usually) thread-safe or at least has predictable threading behavior. Managing side-effects - even without threading - is a major pain in any large code base, and although functional purity can be enforced otherwise in some languages, in most cases you've got nothing to go on. Making your life more difficult by discarding annotations that distinguish between method calls and member access isn't helping.
Of course, in a dynamic languages you're in a tricky spot here - it's hard to refactor, so exposing member access is something that's more work to change later when you discover you need computation or a side effect. However, even so; making a system harder to reason about for the purpose of a fairly pointless architectural purity is usually a bad idea.
The uniform access principle as applied to interfaces is another story; but in general use - I think it sounds nice in theory, but works poorly in practice.
- dragonwriter 13y ago> The uniform access principle as applied to interfaces is another story The uniform access principle is a principle of interfaces, it doesn't apply to anything else.
- emn13 13y agoThat's kind of exactly my point :-). It rarely has a place in the internals of your webapp, and as such makes no sense as a design philosophy for object patterns aiming to be used largely in the internals of your webapp.
- machty 13y agoKeep in mind that Computed Properties are also part of the solution to intelligent, efficient data-binding. CPs in Ember are cached and quite efficient and because they are aware of their dependencies, much of the computation that would otherwise need to go into a dirty-checking approach to data-binding can be avoided. So, Uniform Access is part of it, but I would advise against scrapping an initial implementation of your app using CPs on performance grounds considering that data-binding is the main performance bottleneck in Ember (and Angular).
- pcwalton 13y agoJavaScript hasn't had simple data access for a long time if ever. Computed properties have been widely supported for a long time, there's "watch" [1], and of course there's the prototype chain. ES6 adds proxies, which makes practically everything you might want to do with an object potentially have custom behavior. IMHO, in JavaScript you might as well respect the uniform access principle, since "a.b" meaning simple data access has arguably never existed. [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- emn13 13y agoSince code could be self-modifying; clearly simple-data access has never been a guarrantee. But in practice, today as ever, it's a good guideline. When you see an accessor, it will almost always be fast and side-effect free. Now, part of that is because not all browsers support the features you refer to and therefor these features just don't get used much. But even in languages like C# and python, that have had real accessors for a long time, it's still a good guideline: it's generally considered bad practice to make a slow, side-effectful accessor, and most people don't. Controlling side effects and performance are important, and the uniform access principle has little upside in most non-public code, yet considerable cost in that it obscures one of the few indicators mainstream languages have for these aspects.
- lhorie 13y agoComing from an Angular background, this presentation really made me question my own ideas of whether POJOs should be the "one-true-way (tm)". I always thought POJOs made a lot of sense when you're in a RESTful world, where, to a large extent, your client-side model mimics objects from the database schema. Ok, I'm oversimplifying, but generally speaking, it makes sense to map a web service API point to a User table and compute information on the server end of the web service (I'm talking about highly-relational computations like a `IsUserInTheOffice` property derived from entries in several tables(e.g. Vacation, BusinessTrip); not trivial sugar like `Name = FirstName + LastName`) Realistically though, the highly relational interconnectivity between model entities often require client-side computations. An example from something I've worked on: let's say you're drawing a calendar. What's the maximum start hour/end hour range of entries in a table in your system, plus entries from a 3rd party service (e.g GCal), in a given day? With POJOs it's much harder to refactor when you suddenly need this type of computation, since you need to audit the whole codebase for insertions, deletions and other user-generated updates on all the relevant model entities. All of a sudden, the reactive style of Knockout, or the uniform access framework in Ember look very desirable. To be fair, using things like user.firstName without requiring computations/side effects is far more common than using computed properties, and the author made a good point about the size of code vs usage frequency. And as you point out, making it easy to get into side effect hell from the get-go is probably not necessarily a good trade-off for protecting against potentially expensive, but uncommon refactors.