{"action":"created","issue":{"url":"https://api.github.com/repos/hoodiehq/discussion/issues/106","repository_url":"https://api.github.com/repos/hoodiehq/discussion","labels_url":"https://api.github.com/repos/hoodiehq/discussion/issues/106/labels{/name}","comments_url":"https://api.github.com/repos/hoodiehq/discussion/issues/106/comments","events_url":"https://api.github.com/repos/hoodiehq/discussion/issues/106/events","html_url":"https://github.com/hoodiehq/discussion/issues/106","id":197522635,"number":106,"title":"scoped stores and the type property","user":{"login":"gr2m","id":39992,"avatar_url":"https://avatars.githubusercontent.com/u/39992?v=3","gravatar_id":"","url":"https://api.github.com/users/gr2m","html_url":"https://github.com/gr2m","followers_url":"https://api.github.com/users/gr2m/followers","following_url":"https://api.github.com/users/gr2m/following{/other_user}","gists_url":"https://api.github.com/users/gr2m/gists{/gist_id}","starred_url":"https://api.github.com/users/gr2m/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gr2m/subscriptions","organizations_url":"https://api.github.com/users/gr2m/orgs","repos_url":"https://api.github.com/users/gr2m/repos","events_url":"https://api.github.com/users/gr2m/events{/privacy}","received_events_url":"https://api.github.com/users/gr2m/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2016-12-26T01:36:49Z","updated_at":"2016-12-26T01:48:14Z","closed_at":null,"body":"The current Hoodie Client provides a convenience method to get a store API which is scope to documents with the `.type` property set to the passed scope\r\n\r\n```js\r\nvar scope = 'todo'\r\nvar todoStore = hoodie.store(scope)\r\ntodoStore.add({text: 'Remember the milk!'})\r\n// creates document with {id: 'uuid567', type: 'todo', text: 'Remember the milk!'}\r\n```\r\n\r\nThe problem with the `.type` property is that people might use it for other things than scoped stores. We decided to work around this with a lot of effort, among others we had to implement virtual add / remove events when a user changes the `.type` property\r\n\r\n```js\r\nvar todoStore = hoodie.store('todo')\r\nvar noteStore = hoodie.store('note')\r\ntodoStore.on('change', function (event) {console.log('todoStore event:', event})\r\nnoteStore.on('change', function (event) {console.log('noteStore event:', event})\r\nhoodie.store.on('change', function (event) {console.log('store event:', event})\r\nhoodie.store.update('uuid567', {type: 'note'})\r\n// logs:\r\n// todoStore event: remove\r\n// noteStore event: add\r\n// store event: update\r\n```\r\n\r\nWe made all this in the spirit of [Dreamcode](http://hood.ie/initiatives/#dreamcode), we discussed what the nicest possible API would be and then tried to make it work backwards. And we did.\r\n\r\n### Shortcomings\r\n\r\nImplementing the above APIs adds a lot of complexity and has lead to many very tricky to find errors in the past. For example https://github.com/hoodiehq/hoodie/issues/612 and https://github.com/hoodiehq/hoodie-store-client/issues/95\r\n\r\nAnother major problem is that this behavior is confusing and not predictable. Today I think we tried to be too smart. People don’t really understand what the `hoodie.store(scope)` API does, how it behaves and how it goes together with the rest of the `hoodie.store.*` APIs.\r\n\r\nBut maybe the biggest problem a.k.a. learning I had in the past based on many discussions with the Hoodie Community and people from other projects: a simple API is not helpful if it does not scale. It’s not enough to create Dreamcode for people to get going quickly. It must remain clear and usable, even as the application grows in complexity and usage. And I think in that regard we failed. Not only because of confusing, complexity and bugs, but because we did not embrace the Nr. 1 tip when it comes to storing data using PouchDB / CouchDB: use the `_id` property as much as possible for querying, to avoid secondary indices as much as possible.\r\n\r\nI’m working with CouchDB since over 5 years now, and I have not worked on a single project that does not use the `_id` properties to big extend in order to make the apps and analytics as performant as possible. All projects where we use PouchDB / CouchDB, we would definitely decide to store the above document with `_id` prefixes, like `\"_id\": \"todo/uuid567\"`. Yes that means that the \"scope\" cannot be changed, but that is by design. Using the `.todo` property was a bad design decision. \r\n\r\nI’d like to hear all your thoughts on this, but I think we should come up with something better now, because a change will result in requiring to change every single document stored by Hoodie apps, and we better do this before there are more apps in production.\r\n\r\n### Embracing the primary index\r\n\r\nI think we better embrace the best practise of using the `_id` property from the beginning in Hoodie, with good documentation, API design and mental models, instead of trying to hide away. For the most simple applications people won’t probably need to use it, but for more complex one there should be a clear API.\r\n\r\nI thought a lot about this and my recommendation is we remove the `hoodie.store(scope)` API entirely in favor of `hoodie.store.withIdPrefix(prefix)`. Example:\r\n\r\n```js\r\nvar todoStore = hoodie.store.withIdPrefix('todo/')\r\ntodoStore.add({text: 'Remember the milk!'})\r\n// creates document with {id: 'todo/uuid567', text: 'Remember the milk!'}\r\n```\r\n\r\nIn most ways it will work very similar to `hoodie.store(scope)`, without the need of a `.type` property. We don’t need to explain that the `id` property is special and that it cannot be change, only trough removal and re-creation with a new one. And I _think_ that the meaning `prefix` is clear to most and can be quickly looked up by others. `.withIdPrefix` is fairly self-explanatory, it tells me that all APIs that it returns imply the given `idPrefix`.\r\n\r\nHere are a few things that I don’t find ideal and maybe together we can come up with a smart way to workaround it, or maybe a good documentation has to do\r\n\r\n1. I am not sure if the it would be better if we would find a way to remove the slash `/` from `todo/` and make it an internal implementation detail. But on the other side, I think it’s okay to document and explain that using `/` as separator is the recommended way by Hoodie apps\r\n2. the `_id` prefix is often times used for one-to-many relations. Say my todo app has both lists and todos that belong to the lists. Best practise would be to have id’s like `\"_id\": \"list/uuid567\"` for the lists and `\"_id\": \"list/uuid567/todo/uuid8910\"` for the todos that belong to that list (unless moving items is very common, but let’s leave that out of scope for this example). Now I no longer can find all lists only with `hoodie.store.withIdPrefix('todo/').findAll()`, the result would also include all todos. I have no simple solution to this. But maybe this is such advanced usage that Hoodie can clearly explain both the best pratises and the `.withIdPrefix` API, and it’s up to the developers to filter out the minutes themselves. It _is_ a feature after all to get a list and all its todos with something like `hoodie.store.withIdPrefix('list/uuid567').findAll()`. Or maybe we want to add an extra property which would allow us to query the list documents only. See also the suggestion in #105 which would give us a namespace so there no longer would be a conflict with document properties used by the app.\r\n\r\nThis is how far I got, I’d love to hear your thoughts on this :)"},"comment":{"url":"https://api.github.com/repos/hoodiehq/discussion/issues/comments/269147301","html_url":"https://github.com/hoodiehq/discussion/issues/106#issuecomment-269147301","issue_url":"https://api.github.com/repos/hoodiehq/discussion/issues/106","id":269147301,"user":{"login":"gr2m","id":39992,"avatar_url":"https://avatars.githubusercontent.com/u/39992?v=3","gravatar_id":"","url":"https://api.github.com/users/gr2m","html_url":"https://github.com/gr2m","followers_url":"https://api.github.com/users/gr2m/followers","following_url":"https://api.github.com/users/gr2m/following{/other_user}","gists_url":"https://api.github.com/users/gr2m/gists{/gist_id}","starred_url":"https://api.github.com/users/gr2m/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gr2m/subscriptions","organizations_url":"https://api.github.com/users/gr2m/orgs","repos_url":"https://api.github.com/users/gr2m/repos","events_url":"https://api.github.com/users/gr2m/events{/privacy}","received_events_url":"https://api.github.com/users/gr2m/received_events","type":"User","site_admin":false},"created_at":"2016-12-26T01:48:14Z","updated_at":"2016-12-26T01:48:14Z","body":"ping @hoodiehq/maintainers I would love to hear your thoughts on this ^^ It’s a discussion on a significant Hoodie Client API change, something we have to get right now, so we avoid changes in the future, especially ones that would imply changes in how documents are stored / retrieved"}}
{"actor":{"display_login":"gr2m"}}