
Trello clone with Phoenix and React – 5-part tutorial - tortilla
https://blog.diacode.com/trello-clone-with-phoenix-and-react-pt-1
======
javiercr
Diacode team here. Thank you for sharing the post. This article is part of an
ongoing series of blog posts that covers the whole Trello clone / tribute that
our colleague @bigardone did.

We didn't submitted it to HN before because we were waiting to complete the
whole thing and create a proper index for all the articles. The part 6 will be
published tomorrow and you can expect a few more articles in the next weeks.

I'd like to clarify that this is not a product, it doesn't cover all the
awesome features that Trello has. It's just a learning experiment that we're
sharing with the rest of the world.

Finally, to give you some background, we're a small Rails dev shop (5 guys)
who works remotely. We're now playing with Elixir and Phoenix and having a lot
of fun with it. I'd totally recommend any dev to play with Elixir, specially
if you come from a Rails background.

Kudos to our colleague @bigardone for putting all of this together.

~~~
javiercr
We just added the table of contents with links to all the articles to make it
easier to navigate. You may need to do a page refresh to see it.

~~~
nacs
It would be good to add a "Next" link at the bottom of each part to go to the
next part so people can click through instead of having to scroll to the top
after reading each time.

------
tortilla
Source code: [https://github.com/bigardone/phoenix-
trello](https://github.com/bigardone/phoenix-trello)

Live demo: [https://phoenix-trello.herokuapp.com/](https://phoenix-
trello.herokuapp.com/)

part 2: [https://blog.diacode.com/trello-clone-with-phoenix-and-
react...](https://blog.diacode.com/trello-clone-with-phoenix-and-react-pt-2)

part 3: [https://blog.diacode.com/trello-clone-with-phoenix-and-
react...](https://blog.diacode.com/trello-clone-with-phoenix-and-react-pt-3)

part 4: [https://blog.diacode.com/trello-clone-with-phoenix-and-
react...](https://blog.diacode.com/trello-clone-with-phoenix-and-react-pt-4)

part 5: [https://blog.diacode.com/trello-clone-with-phoenix-and-
react...](https://blog.diacode.com/trello-clone-with-phoenix-and-react-pt-5)

part 6: coming soon

------
dwarner
I'm trying to work out how apps like this and trello calculate and store card
poisition with as little overhead as possible.

It seems obvious that every time you move a card to a column, you recalculate
the order of every card, however that has overhead because you have to send
the new order of every card to the server.

Is there a more efficient way to solve this problem? It seems to me it would
be more efficient to assign a position value for only the card you are moving
relative to those before and after it.

I'm sure trello has solved this

~~~
thedufer
Trello gives each card a `pos` attribute, which is simply a double (64-bit
float). When the first card in a list is created, it is given a `pos` of
16384. When a card is added to the end of a list it is given <pos of last
card> \+ 16384. If added to the beginning, it is given <pos of first card> /
2\. If inserted between two cards, it is simply the average of the two
neighbors.

Finally, if two cards end up with values too close together (just some magic
number - .0001 apart or something) then those cards and some nearby are all
re-numbered.

This means that most of the time you only have to update a single card. In
degenerate movement cases, you might update up to an entire list, but that can
only happen every so many moves (~20 or so, but depends on exact values) even
in the worst case.

~~~
strmpnk
You can get much farther by storing a fraction. Still, a midpoint is not the
most effective point to chose. One solution I've explored is in the form of
fractions generated by the Stern-Brocot tree. The continued fraction
representation is easy to work with and can easily be turned into other
representations.

With that, you could pick ideal points between bounds very cheaply:

    
    
      (1/4, 1/2) → 1/3
      (4/3, 5/2) → 2/1
      (5/4, 7/5) → 4/3
    

In languages with large integers, it's quite easy to store two numbers. In a
language like JavaScript, 53 bits of the mantissa in a double floating point
number give 70+ moves [1] before you'd have to worry about losing precision,
and if that were a deal breaker, a continued fraction is very cheap to store
instead.

If people are interested, I'd be happy to share some implementations I've got
in a number of languages including Erlang and JavaScript (I'm rewriting these
from a prior version I did which used a slightly less optimal path
representation).

[1] These are worst case. Most interactions could survive 1000+ resorts in
practice. I've yet to see any of the components outgrow the 53bit mantissa of
a double in JavaScript. The worse case grows with the Fibonacci sequence which
is easy to see once you learn more about the Stern-Brocot tree structure. Even
when they do grow large though, it's easy to switch to the continued fraction
representation which solves this problem.

EDIT: Here is a short list of indices from a production database where it's
easy to see why fractions are far superior to floating point indices:
[https://gist.github.com/strmpnk/d4afe4bb5bb69b46631b](https://gist.github.com/strmpnk/d4afe4bb5bb69b46631b)

~~~
vbezhenar
Thank you very much. That problem was bothering me for quite a long time, but
I couldn't figure out correct term for googling.

Another solution I made myself is just to use string as a key. If you need to
insert something between "a" and "b", it'll become "an". If you need to insert
something between "an" and "am", it'll become "ann", etc. It uses 26 letters
but probably should use 64 different characters. This way you'll manipulate
strings, they could be easily sorted and you'll figure out next string quite
fast. But they could grow long, so entire recalculation should be done from
time to time.

~~~
strmpnk
Yes. This is very similar if you consider the path on the b-tree with the
alphabet L, R. It doesn't follow traditional lexical sorting though since RRL
(5/2) comes before RR (3/1).

This is handy though. Consider having something at index 'a'. Now find
something that comes right before it. You can't if you use traditional
alphabetical ordering.

------
hakanderyal
That's a really informative tutorial series.

A tip to everyone checking the codebase (JS parts) to learn about building a
Trello-like application, there isn't any optimistic UI updates in this
tutorial app. (eg. after dragging a card to another list, displaying the card
at the dragged position before receiving confirmation from the server.)

When you add optimistic updates to the mix with real time updates, things get
much more complicated. Tracking pending updates, rolling back when something
goes wrong, ordering of updates, reconciliation with server when the client is
missing some updates etc.

I'm building something similar, and these have been most time consuming parts
to build in a reliable way.

~~~
tomjen3
Thats one of the really nice things about react: you can update the state on
the clients copy of the board data, let react change the UI as required, then
let the server send over the new state once it has one, update the clients
state as required and let react deal with the ui updates.

As for reconcillation I would probably just have the server send over the
entire current state of the board when the client connects. It is much easier
and doesn't waste that much bandwidth, which is cheap anyhow.

Am I missing something?

~~~
hakanderyal
The 'happy path' (everything goes right) is easy, as you said.

The hard part for me was making sure the state in the client is always in sync
with server, in a valid state, even when things go wrong.

On a slow connection, another update made by someone else to board may arrive
between the optimistic client update and the server confirmation, which can
lead to a broken state on client.

Or, user may do an update on the optimistically added card, like editing,
while the first action is not confirmed by the server yet. You either need to
queue these actions, or generate the id of the card on client side. And you
need to have reliable 'rollbacks' on the client when server rejects the action
for some reason.

There are many more edge cases like that. I've solved all these problems
eventually, but it took much more time for me than building the happy path.

~~~
eric_bullington
> And you need to have reliable 'rollbacks' on the client when server rejects
> the action for some reason....'ve solved all these problems eventually, but
> it took much more time for me than building the happy path.

I'm sure you figured this out, but having an immutable data structure at the
root of your React application is great for rollbacks. And then maintain an
array with a reference to the various data structures, however deep you need
(within reason), and pop or push them as needed to rollback/roll forward.

~~~
hakanderyal
Yes, I'm using Redux, and never modify the state. But I also needed to
rollback only the rejected action, and keep the rest of the actions that user
did after the rejected action intact. That presented a whole lot of different
edge cases.

I created a solution based on redux-optimist[1], modified to my apps specific
needs.

[1]: [https://github.com/ForbesLindesay/redux-
optimist](https://github.com/ForbesLindesay/redux-optimist)

------
edwinnathaniel
Looks really cool except Part 2 where the ceremonious setup for the front-end
part really point out the issue with JS right now. Other than that, great
work!

------
d1ffuz0r
Why do you need Elixir for building this kind of project? Any real benefits?

~~~
tvon
This use of "need" makes me wonder what the earliest tech is that you could
use to build a trello-ish. I'm thinking it's doable with C, CGI, and
xmlhttprequest....

~~~
thameera
Or a more closer-to-the-metal solution like Node.js?

Joking aside, I wonder if it's possible to write a real-time webapp with C and
CGI. Ok, 'possible' is a strong word; but I'd really like to hear from someone
who'd given this a try.

~~~
mst
Back in the mists of time, there was a thing called CGI-IRC written in perl
that you deployed as an nph CGI script and would then do real time comms; I
think (vague memory) the original authors an ircatwork.com using it and then
eventually started mibbit.

I don't recall seeing one written in C, I think the last time I saw a CGI
script written in C was a some years ago version of Nagios

------
Omnipresent
I'm more interested in the React part of this tutorial. If the backend was
swapped with another framework. can the tutorial still be followed to learn
React?

~~~
burger_moon
I just finished going through this
[http://survivejs.com/webpack_react/introduction/](http://survivejs.com/webpack_react/introduction/)
whole thing building a kanban board using react and altjs. It was really
interesting, though a much simpler version of what was posted in the OP I
learned a lot about webpack and react, and got to try a different flavor of
flux I hadn't experimented with before (alt.js).

I'm excited to dive into the OPs tutorial however. It looks really
interesting.

------
jbhatab
Thank you so much. Been doing lots of phoenix+react and blogs like this are a
tremendous help to the community.

------
wildmXranat
Really nice. I wondered how an elixir app can be designed and this is a cool
resource to use.

