Battle for the Clojure code, or operation, "Military Magnet"

Participated in Clojure Cup 2013 along with Sleigh ingspree that Joes Roma rofh. You've probably seen cutting, and maybe full statement Sled about clojurescript and reactive programming. That turned up the opportunity to try these technologies in combat.

The theme of the competition — 48 hours to saw something using Clojure or ClojureScript. Of different options it was decided to cut the browser Risk, in particular because all existing applications lame interface, or is written in Flash, or even worse, Silverlight, or in some way spoil the experience. Collectively I think of a good name — War Magnet.

Without thinking twice, we decided to write the server in Clojure and ClojureScript on the client, using shared code. Of the four participants, only the Sled was at least some writing experience of Clojure code, and the other two had only experience of solving a few dozen puzzles 4clojure.

Server


On the server side, I will not tell much for the competition, I never once to the server side and not touched. As a database we chose one of two options:

The first thing that comes to mind with the combination of words and Clojure database — Datomic. Very interesting to try, but none of us had absolutely no experience with dinamikom, even a couple of hours, and we feared that another completely new concept in a project can ruin the undertaking and we do not have time.

So the choice fell on the most fashionable in recent years, the database is PostgreSQL.

Tried to use clony from si14 as a preset, but for us it was too hard, it was very unclear how to extend your things. After half a day after the start made to the new repository without clony, and quickly moved all the developments there.

Will list the libraries that we used on the server, compojure, ring, korma, friend, cheshire, http-kit. Vaguely heard the stern, hard-hitting comments, and all the other details about this Sergei promised to describe in blog.

Client


Choosing which technologies to use on the client. There are new-fangled core.async, but he had fallen due to the fact that all tutorials and management write about how cool it manage the data, and then are beaten to a Dom'e at selectors. It is believed that this is a flawed concept and should just accept that HTML is the way we build interfaces. But if selectors to join — we like on the side from his work, and for any changes in the structure of the interface is very neat and tedious to saw the damn selectors.

Have a good looking jet library for ClojureScript is the combination of javelin and hoplon. Though they are good from a conceptual point of view, but there is nobody optimizations were not engaged because they are already very slow — the simplest Todo-example is noticeably slow, even on desktop Firefox. The development of more complex applications would become a pain because of the constant brakes of the interface, decided to deny.

In my last project at work Sasha and Roma are using post React in conjunction with coffeescript, and they really like him. Here it and took. On Friday, before the competition, I started to deal with React'ω and began to write library binding for him. Completed the first version we have on Saturday to the hour of the day.

Here is the React:
the
var HelloMessage = React.createClass({
displayName: 'HelloMessage',
componentWillMount: function() {
...
},
render: function() {
return <div class="smth">{'Hello' + this.props.name}</div>;
}
});


This XML-like syntax easy and intuitive in JavaScript. But to integrate it with Clojure even the thought arose: inspired by the syntax hiccup, we made this variant:

the
(defr HelloMessage
:component-will-mount (fn [] ...)
[this props state]
[:div.smth (str "Hello" (:name props))])

Some problems arose at the junction of the clojurescript and react. For example, we initially tried to directly use ClojureScript'the new data structure as a condition, but react within itself makes a shallow copy, not transferring a prototype, and we are all broke. As spike began to put our state in the field state.state, and to get it out.

Of course, it is hidden in the library, but because of this I had to do a helper assoc-state and assoc-in-state that should be used to change the state. One of the developers of React — Pete Hunt — in irc suggested the same workaround. Maybe some will be able to make friends more adequate way.

Overall, on the client, we all the state is stored in a single atom, in the same data structure at the desired portions pass the controllers-deeper and deeper. With JavaScript we would have happened to the local Apocalypse, but in Clojure code data structures remotely, so no problems arose.

For communication between client and server, we used json, because as cool clowny format edn is deserialized on the client slower by approximately the procedure and cljson, which retains Clojure structure, ridiculous and incomprehensible. And that was a mistake!

Then I got problems with the fact that :keyword is serialized as "keyword stuffing". Clojure code you can say :keywordize-keys — do in dictionaries of the keys keywords. But this all does not solve the problem — not all the keywords were the keys in the dictionary, and creates others — not all the keys in the dictionaries were the keywords. Especially frustrating was with the numbers — Clojure server can't (keyword 1) and returns nil, and ClojureScript do :1, but it later turns out that the deserialized with specola keys from json'and contained within a string, not a number, ie (keyword "1").

Since the second half of Sunday we lost at least an hour and a half on this issue, and now on the code here and there placed the crutches. Had originally use cljson, and probably will remake it.



Here is the code for this window:

the
(defr Attack
[C {:keys [attacker attacking defender defending attack!]} S]
(let [[aname {:keys [coordinates]}] attacker
[dname dmap] defender
[x y] (xy-for-popover coordinates)]
[:div.popover {:style {:display "block" :left x :top y}}
[:div.popover-content
[table
[:thead [:tr [:th (name aname)] [:th (name, dname)]]]
[:tbody [:tr [:td attacking] [:td defending]]]]
[:div.btn-group
[:button.btn.btn-warning {:on-click #(attack! 1 aname dname)} "Attack"]
[:button.btn.btn-danger {:on-click #(attack! (dec attacking) aname dname)} "Blitz"]]]]))

In my opinion, everything happening here is pretty clear. And if anyone is annoying here, the number of brackets, so remember that in this HTML them even twice: <div></div> four [:div]. Plus, when editing paredit helps a lot with him in parentheses are not confusing at all.

Overall, there was a feeling that ClojureScript and React — umatovy bunch you can use and need!

Competition


Cry about participate in the Clojure Cup Sanya threw two weeks before, at the same time agreed that we will do, and about what technologies to use. But, as usual, for such competitions, almost no one is prepared, despite any promises to myself and comrades, and we are no exception. Though the library we started to do on Friday night (it is allowed)!

He Clojurecup lasted exactly 48 hours weekend, from 00:00 UTC Saturday until 00:00 UTC Monday. Our time is three o'clock.
They gathered Saturday morning in the office, we spent somewhere between half a day on dodeljivanje library, all sorts of setups and other buildup to make it working.

On Saturday we got the authorization through Mogilevsky Person (a very good thing!), sending messages between the client and the server through websocket, a little shared code between client and server, in the database of signs with the users, games and a log of events. Another client began to draw classic Risk map with the territories and highlighted on hover. Last commit 22:30.

Sunday morning I drew us a nice logo, and then I have Sunday all blurred into one continuous pedaline code. Bondage playing cards and server moves-attacks-refill and so on actually left at the end.



By the evening it was still in a disassembled state, by eight o'clock we slightly altered the format of the map description and for the first time uploaded it on the server. As yet it is unclear whether we have time to finish the game to minimal operating status, we decided to continue until you will see the chance and the desire/ability to do something.

Somewhere around eight or nine, we moved to another room which was much better lighting, cool and closer to the corner with tea and coffee :) it so Happened that all the time I could see the chance to make a working version, energy and enthusiasm was enough and we sawed-sawed him right up to the deadline.

Commit with a working game and a button "finish the course":

the
Mon Sep 30 2013 02:59:54 GMT+0300 (EEST)



Unfortunately, we have in production version crept into the bug with the download of map data from a file. Locally it works, but when you package in the uberjar — no, it must be loaded from resources. The commit with the fix for this was 5 minutes before the finish, but he was unsuccessful, and we have a lined version, in which play is impossible. There were just fifteen minutes.

According to the rules, and we have no right to dispelleth or put another version somewhere. Now there is a vote, it will end on Thursday and Friday can be updated and show all working.

There were more than 90 teams. We got 6.5% of the total commits number of commits of all teams, and there is at least one team, which was even more seem to 9.15%. For vote selected team 42. I have for some reason, in Firefox their site does not work properly. In chrome works.

I promise that on Friday we will publish a working version, and yet on the page of our team for us. vote!
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

The release of the new version of the module modLivestreet 0.3.0-rc

mSearch: search + filter for MODX Revolution

Emulator data from GNSS receiver NMEA