Re-frame db organization - clojure

We have our Re-frame app db organized like this (simplified for this post):
{:meta {:page/search {:page/component #'...} :page/details {:page/component #'...}}
:widget/base {:cur-page-id :page/search}
:page/search {:page/route {:query-params {:q "1"}, ...},
:page/details {:page/route {:query-params {:q "2"}}, ...}
Consider everything under :meta immutable.
The base widget takes care of rendering the currently selected page by subscribing to [:widget/base :cur-page-id] and then selecting [:meta cur-page-id :page/component].
It also needs the :page/route of the current page, which the pages themselves also need. It gets this one by subscribing to (fn [db] (get-in db [cur-page-id :page/route])). This may be an anti-pattern because we now have a subscription to the entire db.
We could refactor this, but maybe it’s good to know first what this costs in performance. Is there a way to measure this properly?
We could e.g. store the routes under the :widget/base entry where pages would look up their own routes via a subscription that selects only :widget/base :routes, avoiding a subscription to the entire db.

For measuring performance of subscriptions https://github.com/Day8/re-frame-trace is recommended.

Related

Shared resource in functional programming

Context
I am writing an app using Clojure and following the functional programming paradigm. In this app I have two HTTP endpoints: /rank and /invite. In /rank the app ranks a list of costumers based on their scores. In /invite the app receives an invite from one costumer to another and this should yield changes on the scores of some costumers.
Problem
Data from costumers are kept in a single vector of maps called record.
Putting aside referential transparency for a moment, record should be a shared resource between the endpoints, one reads it and uses it in a ranking function to respond an HTTP request and the other reads it and updates scores in it.
Now, with functional programming in mind, record cannot be updated, so the /invite endpoint should read it and return a new record', problem is, /rank endpoint is setup to use record, but when a new record' is generated it should use it instead of the original one.
My ideas for solving this
I understand that in this context the whole app cannot be fully, functionally speaking, pure. It reads initial input from file and receive requests from the external environment, all of which renders functions that deal with these parts not referentially transparent. And almost every program will have these small portions of non-functional code, but in an attempt of trying not to add more of these non-functional functions to the app and this app being just to exercise some functional programming, I am not persisting record to a database or something, because if this were the case, problem would be solved as I could just call a function to update record on the database.
My best idea so far is: The endpoints are created with a routes function from Compojure, so in the /invite endpoint I should process the new record' vector, and recreate the /rank endpoint supplying it with record'. This part of recreating /rank is what I am struggling at, I am trying to call routes again and define again all the endpoints in the hope that it will override the original call of routes, but as expected, as I believe Compojure follows functional programming, once created, the routes are immutable and a new call of routes won't override anything, it will just create new routes that will be left in the void, not attached to the HTTP requests.
So, is it possible to do what I want with pure functional code? Or it is unavoidable to break referential transparency and I should persist record to a file or database to update it?
PS.: I don't know if this is relevant, but I am new to Clojure and to any sort of web interaction.
Clojure (in contrast to Haskell) is not pure and has its own constructs to manage changes to shared state. It doesn't isolate impureness using a type system (like IO monad in Haskell) but promotes using pure functions and managing the state with different types of references (atom, agent, ref) defining a clear semantics how and when the state is changed.
For your scenario Clojure's atom would be the simplest solution. It provides a clear contract on how its state is managed.
I would create a var holding your record within an atom:
(def record (atom [])) ;; initial record is empty
Then in your rank endpoint you could use its value using deref or with # as a syntactic sugar:
(GET "/rank" []
(calculate-rank #record))
Whereas your invite endpoint could update your record value atomically using swap!:
(POST "/invite/:id" [id]
(invite id)
(swap! record calculate-new-rank id)
(create-response))
Your calculate-new-rank function would look like that:
(defn calculate-new-rank [current-record id]
;; do some calculations
;; create a new record value and return it
(let [new-record ...]
new-record))
Your function will be called with the current version of the data stored in the atom and other optional parameters and the result of your function will be installed as the new value of your atom.

Clojure and Page Object Pattern alternatives

I am trying to write Webdriver checks using Clojure. If I was using an object oriented language, I would use the Page Object Pattern. I think modeling a page as an object makes sense, I could create some java classes for the page objects and all would be well.
I want to know if there are any alternatives to the page object pattern using a functional style that maintain the same level of clarity.
A page (especially a RESTful one), can be thought of as a function from request to render (and, if you want to take the next step, the render exposes some set of new requests).
The translation from sending a request to page to applying a function to arguments is simple, and also quite comprehensive.
If you are providing a complex webapp, try taking a functional view of requests. GET can retrieve data, but should not modify server side state, use PUT to create a resource, use POST for mutation.
Once you write your controllers in this way, you can do quite a bit of testing without webdrivers. It should mostly suffice to provide a mockup of the request input to the controller, and verify some properties of the rendered result (for GET) or the storage state (for POST AND PUT).
I have even found it useful to break off request parsing and rendering into separate functions, in order to simplify the testing of the data processing that should happen in the middle, ie.:
(defn parse-home
[request]
(let [user-id (-> request :params :session :id)
account (get-user user-id)]
{:user-id user-id
:account account}))
(defn do-home
[user-id account]
(let [messages (get-messages account)
feed (generate-feed user-id)]
(update-user user-id :last-visited (java.util.Date.))
{:messages messages
:feed feed}))
(defn render-home
[request messages feed account]
(let [messages (mapv summarize (filter important messages))
feed (sort-by :priority feed)
template (-> request :page :template)]
(render template (assoc request :data {:messages messages :feed feed :account account}))))
(defn home
[request]
(let [{:keys [user-id account]} (parse-home request)
{:keys [messages feed]} (do-home user-id account)
body (render-home request messages feed account)]
{:status 200
:content-type "text/html"
:body body}))
Each element of the home page logic can be verified by providing one of these functions with the right input, and verifying some properties of the output. There is no need to mock up state or simulate page interaction unless you are also using clojurescript on the front end (and even in that case the logic you want to verify can be abstracted from the interface of the browser to avoid the need for replay testing).

Ember Data Sync - LocalStorage+REST+RealTime+Online/Offline

We have a combination of requirements in terms o data access.
Pre-load some reference data.
We need reference data to survive browser restarts instead of just living in memory to avoid loading it all the time. I'm currently using the LocalStorageAdapter for that.
Once we have it, we would like to sync changes (polling or using Socket.IO in the background and updating the LocalStorage could do the trick)
There're other models that are more transactional, where we would need to directly go to the Server and get/save them. It would be nice to use something like the RESTAdapter for that.
Lastly, there're some operations that should work off-line and changes should be synced later.
To make it more concrete:
We pre-load vendor and "favorite products" into Local Storage. We work offline with those.
We need to sync server changes to vendor and product information.
If they search the full catalog, that requires them to be online.
When offline, we need to allow users to add something to their cart or even submit and order. We would like to queue this action and submit it when they have an Internet Connection.
So a few questions are derived from this:
Is there a way to user RESTAdapter in combination with LocalStorage?
Is there some Socket.IO support? (Happy to do this part manually)
Is there Queueing support? Ideally at the Ember-Data level.
I know we will have to do a lot of this manually and pull together the different lego pieces, but I wanted to ask for some perspective from experience Ember devs.
You definitely can do this. Like you said you're going to need to do a lot of lego pieces to put it all together.
You'll need to take the RESTAdapter and LSAdapter and create a hybrid. We've done something a little similar at my work, but it only goes one way (from server to client, not reverse).
That being said, I'd just like to pose a few questions:
How much do you plan on storing in localStorage, and do you have an eviction plan in place? Local Storage is generally small for most browsers, though the implementation is the same across most browsers (not implemented until IE8). IndexedDB gives you a much larger chunk of space, though implementation isn't available until later versions of IE.
Depending on performance needs, I'd recommend storing localStorage first, then attempting to persist to the server, if that works pop from localStorage, if it doesn't leave it in there for your adapter to attempt at a later date. (I'd look into using Ember's schedule or scheduleOnce or a slew of other convenient helpers that work within the run loop, http://emberjs.com/api/classes/Ember.run.html#method_schedule).
Called by the store when a newly created record is
`save`d.
It serializes the record, and `POST`s it to a URL generated by `buildURL`.
See `serialize` for information on how to customize the serialized form
of a record.
createRecord: function(store, type, record) {
var data = {};
var serializer = store.serializerFor(type.typeKey);
serializer.serializeIntoHash(data, type, record, { includeId: true });
// build up a model that knows the url, the method, and the data to post
// store it to local storage in some queue to save
// schedule it to save to server later, keep track of the record since you'll
// need to update the record with new information later that could come down
// from the server
return this.ajax(this.buildURL(type.typeKey), "POST", { data: data });
},
Honestly I think the most difficult thing you might experience will be how you handle ids when you don't really save it to the server. Good luck

How to update just 1 record in Ember.js with Ember-data? Currently save() and commit() on 1 record actually updates all records of model

Premise: My question is based on my research of Ember-data, which may or may not be correct. So please correct me if I have any misunderstanding. The examples are running with the latest ember as of July 2, 2013.
To edit a record of my model, just 1 record, you need to call this.get('store').commit() or this.get('model').save(). However, downstream of either of these functions actually have to update all of the records of the model, even those left untouched. So this is quite inefficient, especially if the model has numerous records.
What's the best way to update one and only one record when I'm saving the edits of one record?
UPDATE: this problem only occurs for the local-storage-adapter, not the RESTAdapter.
UPDATE #2: I did have a huge misunderstanding. Everything is okay, save() and commit() both update just 1 record, I've been fooled by local storage adapter _saveData's JSON.stringify(this._data) which printed out all records. I assumed that whatever it printed out was the data that is changed, but turns out in _saveData's callers the records in updateRecords and _didSaveRecords were just the single record I was changing. The statements below about different objects containing "all records of the model" can no longer be duplicated. I guess I misread the debugging information.
It makes sense because _saveData uses localstorage, which currently can only setItem for an entire object, which in my case is the model containing all the records. Since localstorage can't update individual entries of that object, the JSON must contain all the records.
Details:
Running Examples:
this.get('store').commit() is used in doneEditing of updating a post this jsbin.
this.get('model').save() is used in acceptChanges of updating a todo this jsbin.
If you turn on Chrome debug and walk into the above two functions, you'll see something similar to below:
Downstream, there is currentTransaction or defaultTransaction, and both have all records of the model inside.
In the case of get('store').commit(), it eventually calls DS.Store's commit, which in turn calls: (see github)
get(this, 'defaultTransaction').commit();
In the case of case of get('model').save(), it eventualy calls DS.Store's scheduleSave and flushSavedRecords, which call: (see github)
get(this, 'currentTransaction').add(record);
get(this, 'currentTransaction').commit();
Note at the end a commit() is called on xxxTransaction, this is DS.Transaction's commit().
DS.Transactionscommit()has acommitDetails, which is based on xxxTransaction, socommitDetails` also has all the records of the data. (github)
Then DS.Adapter's commit and save are called and indeed every single record is updated (github):
this.groupByType(commitDetails.updated).forEach(function(type, set) {
this.updateRecords(store, type, filter(set));
}, this);
(minor side note/question: when was commitDetails set to "updated"?)
I know that DS.Adapter can be customized, but clearly the problem of saving more than one data (i.e. all of the model entries) are set from DS.Store's commitDefaultTransaction and currentTransaction.
Somehow I feel it would be a bad idea to tinker with DS.Store or anything upstream of DS.Adapter, like making my own version of save() and commit(). Basically I am reluctant to customize anything I'm told not to, since there might be ugly side effects.
So what should I do if I want to use Ember data but can only afford to update one record only at a time?
You can create a new transaction just for managing that record, using transaction() method of the store. This transaction has the same api as the defaultTransaction.
var transaction = this.get('store').transaction();
transaction.add(model)
transaction.commit();
Committing this transaction won't affect other changes. See this blog post for further ideas.

How to deal with restful "actions" on an object.

So I want to know what are the best practices for doing actions on a object that doesn't change the state of the object. If that doesn't make sense bear with me, I think the tweet example explains what I am trying to say.
I understand the basics like described here:
What are the best/common RESTful url verbs and actions?
And how it works when updating/getting/deleting etc an object. But what about actions that don't change the state of the object?
For example say we have a tweet object:
GET `/tweets (gets a list of tweets)
GET `/tweets/new (gets a new page to create a new tweet)
POST `/tweets (posts data to server to create new tweet)
GET `/tweets/:id (get a single tweet)
GET `/tweets/:id/edit (get a page to edit an exisiting tweet)
PUT `/tweets/:id (put data to server to edit exisiting tweet)
Delete `/tweets/:id (delete an exisiting tweet)
This makes sense to me. But how do i form the URL for reply/ follow / retweet/ favorite, some of which don't actually change the state of the tweet?
Should I do something like below?
POST `/tweets/:id/reply (post the reply message to the server)
POST `/tweets/:id/follow (post a boolean? yes I follow?)
POST `/tweets/:id/retweet (again post a boolean?)
POST `/tweets/:id/favorite (ditto)
Or do a
POST `/tweet/:id/actions (Do a post with the action I want to take as a parameter)
Or is there no "standard way".
Anyways thanks for the help!
Great question.
As always, it helps to switch the framing to nouns instead of verbs. What are the resources you're acting upon when you reply/etc.? And can those resources be fetched/addressed also?
In each of the cases you mentioned, I think the answer to the second question is yes. And in fact, Facebook's Graph API and GitHub's REST API both follow this approach.
E.g. for replying:
GET /tweets/:id/replies to get a list of tweets that were in reply to the given one
POST /tweets/:id/replies to create a new tweet in reply to the given one. The important part here is that success is a 201 Created w/ the Location header set to the created tweet's endpoint, e.g. /tweets/1234.
(Deleting a reply is then just deleting a tweet.)
Following/retweeting/favoriting are a bit trickier because the "nouns" are lightweight connections, and in fact, I just asked a Stack Overflow question for the "best" way to expose those:
RESTful API design: best way to CRUD lightweight connections?
You can see on that thread the specific way(s) you might implement following/retweeting/favoriting.
Hope this helps!