Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial structure for the second sprint #46

Open
wants to merge 55 commits into
base: master
Choose a base branch
from

Conversation

meditans
Copy link
Contributor

@meditans meditans commented Oct 31, 2016

Description

The main aim of this sprint is translating a mock roles page and the related role edit page, trying to develop approaches that scale for the problem of how to link back server errors to the part of the ui in which they happened. The scalable solution found for this server-side problem will be then contrasted to the obvious solution for client-side validation, and I'll try to unify the approaches in a single API.

A mock API and server will be constructed, following the architecture of the last sprint, to simulate the behavior of the page.

A particular focus will be put in writing high-level code which expresses complex UI interactions: for example, when the Product checkbox is ticked, all the boxes in the submenu should be (and vice-versa).

If there's time at the end, contributing back some code to the libraries we're using/fixing haddocks would be a worthwhile accomplishment.

Tech Stack

reflex, servant, servant-reflex

@saurabhnanda
Copy link
Contributor

saurabhnanda commented Oct 31, 2016

  • There's also a role list UI
  • Where does the mapping of permission "label" (or "ID") => human-readable name come from? eg. edit_product_content => Edit product textual content, edit_product_price => Edit product price

@meditans
Copy link
Contributor Author

meditans commented Oct 31, 2016

  • Sure, I forgot to put the other link, editing!
  • Do we have a datatype for Permissions, defined somewhere in our codebase?

@meditans
Copy link
Contributor Author

What we did in this sprint

We used reflex to model the users and roles overview and editing pages: doing
this required:

In the shared and server code

We implemented the domain logic regarding users, and roles. On the server side,
we expanded the mock server done last time, using STM between endpoint to
simulate persitence of roles without the need of an actual database (using the
enter family of functions). This is a great way to use simple servers when
prototyping the frontend.

On the clientside

Reflex templating

One of the first obstacle we encountered was the need to convert the html mock
pages in reflex code. While I initially did this by hand, a smarter solution was
needed; moreover we noticed that markup and signal logic were too interwined to
give a satisfactory experience.

I discovered in the meantime that in the templating world, there are solutions
like blaze-builder which convert automatically from html. Although something
similar for reflex could be constructed, there would still be the problem that
whoever modifies the css has to be able to read haskell code, and this is not
optimal. Moreover, the monadic structure is overloaded by having to keep trace
of both markup and signal dependency. This leads to unpleasant code.

We solved all this problems by extending a jsx quasiquoter in such a way that
reactive values can be embedded at any point in the dom, and the values
generated by them is retrieved seamlessly. So the monadic structure has only to
deal with signals now, and css is editable by a third party.

Validation

We vetted the existing solutions for data validation. Our goals were mainly:

  • Creating a system that permits to mix client and server-side validation.
  • When the error is transmitted back, putting the errors near the places in
    which it was generated.

We discovered that the formlets/digestive-functors approach, while very
interesting with respect to its compositional properties, is not very well
suited to a javascript heavy application (it has been thought with traditional,
not reactive, web pages in mind).

So we created a typeclass based approach which permits the construction of
errors that have the same shape of the data they refer to. This enables
re-aligning the errors with the place in which they have been generated, and
mixing client side and server side validation by composition. Arguably, this
approach could be extended to give a library which deals with this kind of
validation (among the things that would be needed: automatic generation of
Shaped data definition, using template haskell; automatically deriving the
instances that are needed by servant to serialize and deserialize the errors
when they are transmitted back and forth to the server; dealing with the fact
that the validation on the server side could be monadic, and providing
convenient monad embedding functions).

General structure of the application

On the clientside, we used a way to structure a large application, which leaves
the user free to decide when to sync with the server, in order to gain
reactivity where needed. On the other hand we also saw that there are some
natural sync points, which are dictated by the need to not send too much
information to the client if the task could be accomplished more easily by
communication with the server (autocompletion in a search box for a large
database is a relevant example). While that is a very powerful approach, the
helper functions tend to be a bit complex, so I feel that is a bit complex, and
they should probably be in a library. Also, in the presence of client-side
routing, this architecture may not be necessary. This is a point on which I
still don't have a definitive answer.

On the smaller end of the scope, we used with great effect the RecursiveDo
extension, to enable simple definition of signals depending mutually in each
other: by doing so we encountered a bug which lead to the understanding that one
should avoid "tying the knot" on non-reactive values (in practical terms, one
should try to put the values that are not reactive as high as possible in the
recursive do block).

I felt that the learning curve to understand how to structure an application was
a bit steep, mainly for the lack of documentation/tutorial on how to do that.
However, once done the first time, it becomes easier and easier, and pattern
become to emerge clearly.

Client side routing

We also have been trying to tackle the problem of client-side routing: we are
using the servant-router library to construct a servant-like navigation (it
automatically takes care of low level js details, deserializing values from the
address bar, and serving a mirrored structure on the backend (which always
returns the same page)). We have not been able to solve a bug with the routing,
so at this moment this has to be considered incomplete, and further
experimentation is needed.

@saurabhnanda
Copy link
Contributor

Shall I merge or wait for the following?

  • Fix for routing
  • Integration with existing jquery widgets
  • Unification of login and role UI into a single app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants