<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0AARH0yfyp7ImA9WhBbF0w.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299</id><updated>2013-05-16T18:55:45.397+03:00</updated><category term="Speeches" /><category term="Python" /><category term="Approvals" /><category term="Reading" /><category term="Mocks" /><category term="NancyFX" /><category term="Hackatone" /><category term="MVC" /><category term="CS101" /><category term="AJAX" /><category term="UI" /><category term="BabyStepsBackbone" /><category term="Candidate" /><category term="ITJam" /><category term="Udacity" /><category term="NodeJs" /><category term="ELMAH.MVC" /><category term="Node.js" /><category term="Retrospective" /><category term="Open source" /><category term="TDD" /><category term="Git" /><category term="Conference" /><category term="DDD" /><category term="Applications" /><category term="Clean Code" /><category term="Video" /><category term="DAL" /><category term="Cloud" /><category term="Mobile" /><category term="Social" /><category term="Foundstyles" /><category term="Code Kata" /><category term="Trackyt.net" /><category term="Backbone.js" /><category term="CSS" /><category term="REST" /><category term="SPA" /><category term="Continuous" /><category term="GitSVN" /><category term="Design" /><category term="Tips" /><category term="BeerNCode" /><category term="E-conomic" /><category term="Refactoring" /><category term="KievAltNet" /><category term="Mind" /><category term="Life" /><category term="Stanford" /><category term="GitHub" /><category term="NuGet" /><category term="Agile" /><category term="Linq" /><category term="HTML" /><category term="InsideMVC" /><category term="Tools" /><category term="asp.net" /><category term="CSharp" /><category term="SearchEngine" /><category term="JavaScript" /><category term="TypeScript" /><title>Alexander Beletsky's Development Blog</title><subtitle type="html">Issues of development, testing, maintenance and &lt;a href="http://trackyt.net"&gt;management&lt;/a&gt;</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.beletsky.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.beletsky.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>196</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/abeletskyblog" /><feedburner:info uri="abeletskyblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;A0AARHo7cCp7ImA9WhBbF0w.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-1475800976270515189</id><published>2013-05-16T18:55:00.000+03:00</published><updated>2013-05-16T18:55:45.408+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-05-16T18:55:45.408+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="GitHub" /><category scheme="http://www.blogger.com/atom/ns#" term="Mind" /><category scheme="http://www.blogger.com/atom/ns#" term="Open source" /><title>Github as blogging platform</title><content type="html">    &lt;p&gt;        No, I'm not going to talk about creation some &lt;a href="https://github.com/alexanderbeletsky/wonka"&gt;github-backed&lt;/a&gt; blogging system. I would like to talk on some blogging style I tried to apply recently.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The problem is, technical blogging is difficult. I usually have a lot of ideas or know-how's while I create some code. It's just hard to blog about. As you didn't do the blog post during coding, you might forget some details or simply loose the encouragement to blog about it.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        As I mentioned in my &lt;a href="http://www.beletsky.net/2013/04/building-single-page-applications-with.html"&gt;previous&lt;/a&gt; post I recently created some code that contains Backbone.js + Express.js boilerplate code that could be great start for building single page applications. I felt I need to document it somehow, so even myself will remember what's going on there. So, I put some &lt;a href="https://github.com/alexanderbeletsky/backbone-express-spa/blob/master/README.md"&gt;README&lt;/a&gt; file there. Usually, I don't write much documentation, but during writing it I realized that it's a kind of blog post or tutorial I'm writing immediately after I created something.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I liked the way how it went. First of all, Markdown is great for technical blogging. I still use HTML and feel a but ashamed by that fact. It's so easy to format and place code examples inside with Markdown (and it looks minimalistic and great on github). Second, the content of resulted readme file, pleased me much.. I felt it's the same as blogging, but a bit.. more interesting, or so? So, I twitted about and great surprise for me, repository got 200 stars and 20 forks, got &lt;a href="http://javascriptweekly.com/archive/128.html"&gt;mention&lt;/a&gt; on &lt;a href="http://javascriptweekly.com/"&gt;JavaScript Weekly&lt;/a&gt; and raised some &lt;a href="https://github.com/alexanderbeletsky/backbone-express-spa/issues"&gt;questions&lt;/a&gt;. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The same as blogging, but instead post you have repo with README + some valuable code. Instead comments, you got issues and pull requests.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        That was really motivating experience. I think I would like to repeat it from time to time.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=oPULs7plF6M:hKSJhleExYw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=oPULs7plF6M:hKSJhleExYw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=oPULs7plF6M:hKSJhleExYw:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=oPULs7plF6M:hKSJhleExYw:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/oPULs7plF6M" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/1475800976270515189?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/1475800976270515189?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/oPULs7plF6M/github-as-blogging-platform.html" title="Github as blogging platform" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/05/github-as-blogging-platform.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQMQXw9fyp7ImA9WhBUEkg.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8148951530202025436</id><published>2013-04-29T20:26:00.000+03:00</published><updated>2013-04-29T20:26:20.267+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-29T20:26:20.267+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="SPA" /><category scheme="http://www.blogger.com/atom/ns#" term="Conference" /><title>Building Single Pages Applications</title><content type="html">    &lt;p&gt;        This is transcript of talk I gave on &lt;a href="http://www.msswit.in.ua/"&gt;#msswit&lt;/a&gt; conference 25 April 2013.&lt;br /&gt;
    &lt;/p&gt;    &lt;script async class="speakerdeck-embed" data-id="2e8c91508fbe0130b23722000a1c4609" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"&gt;&lt;/script&gt;&lt;br /&gt;
    &lt;h2&gt;        What is SPA?&lt;br /&gt;
    &lt;/h2&gt;    &lt;p&gt;        If you just imagined the pools and saunas and massage rooms, this is, unfortunately, not the thing that I going to talk about. We'll check out new concept of web applications, that are called - Single Page Applications.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        From technical perspective SPA means the web application, that being loaded as one HTML page and redraws it's UI without round trip to server. That sounds not so exiting, but we can see that SPA is much more than that.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        GMail is canonical example of single page application. It was not the first single page application though, it became very popular and gathered a lot of users. That was probably the first time the masses of people realized new user experience - application that works in browser, behaves similar to application on desktop. So, SPA opened a of new opportunities and abilities for software developers to release and promote their applications in web, which is in common case a much easier task, comparing to desktop applications. And new approach need to be taken to create such applications.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;        API oriented architecture&lt;br /&gt;
    &lt;/h2&gt;    &lt;p&gt;        Before we jump into SPA details, let's talk about the architecture that would allow to build apps in that way. Popularized by &lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt; it's being adopted by many vendors and became kind of default. We are talking about 'API oriented' architecture.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Basically, it's just a deviation of classical 'Server-client', where we have server that provides an open API.. and where client is browser, powered by JavaScript engine.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It's quite typically that server and client are communicating through HTTP, using JSON as payload format and relying on REST principles. I'm saying &lt;i&gt;typically&lt;/i&gt;, since it's not always the case. Some apps might takes XML and use RPC instead of REST, but that actually doesn't really matter.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Client is browser, that runs JavaScript code. JavaScript code is requesting the data and updating the DOM. Few years ago, jQuery was the primary tool of making such applications. Nowadays, we see MV* JavaScript frameworks are gaining a lot of traction and simplifying front-end development. It's not only about simplification, but also bringing the architecture principles on front-end, something that we haven't seen earlier.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;How to build Single Page applications?&lt;/h2&gt;    &lt;p&gt;        We have a bunch of technologies, server and client that would allow to do that. ASP.NET MVC, Web API, NancyFX, ServiceStack, Express.js, RoR.. etc, on server and Backbone.js, Knockout.js, Angular.js, Marrionette.js, Durandal.js etc. from client.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It gives a lot of options, actually. All of them have their pro/cons. I've used to use ASP.NET MVC as platform to build open API's and was quite happy with that. Nowadays, I'm using Node.js / Express.js and it works really great, as well.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The truth is, with SPA, the front-end technology plays a bit more significant role. Of course, server still performs important role for authorization, data access, business logic.. but in API oriented architecture is turns to be a kind of CRUD exposed through HTTP.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        As for front-end, my experience lies in Backbone.js. Preventing the questions, I would say - Backbone.js is not perfect (as there are nothing perfect in this world). Bare Backbone.js app would require a lot of manual coding, but it would also allows to see some important implementation details that could be good for general SPA understanding.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Server architecture&lt;/h2&gt;    &lt;p&gt;        Server is responsible for two principal things. First, it provides with API. Second, it server the master page (again, it's not always the case, master.html could be places in some static resource server).&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Master page, is the one that being rendered in browser should bring basic DOM structure + reference the JavaScript code to initialize and run application. That's it.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        As always, it's important to think about scalability. Doesn't matter what technology you pick up, it's able to scale and hanlde more incoming request with given response time is vital.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Client architecture&lt;/h2&gt;    &lt;p&gt;        Scalability is important here, as well. That's a different scalability, though.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I liked the way &lt;a href="https://twitter.com/derickbailey"&gt;Derick Bailey&lt;/a&gt; stated in one of &lt;a href="http://javascriptjabber.com/056-jsj-marionette-js-with-derick-bailey/"&gt;JavaScript Jabber&lt;/a&gt; show:&lt;br /&gt;
    &lt;/p&gt;    &lt;blockquote&gt;        ... scalability in this case is not the number of users running the code at any given time. It’s the number of features in the system, how those features interact, and how you can start up and shut down and do all these things with these different features so that your application can grow in size, grow in features, and grow in capabilities.&lt;br /&gt;
    &lt;/blockquote&gt;    &lt;p&gt;        That's were there the JavaScript pattern, MV* frameworks are shine. And without simple modularity, it's very hard to build scalable JavaScript applications.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Require.js and AMD&lt;/h2&gt;    &lt;p&gt;        Modularity is important. Each module represents some small piece of application functionality. The problem that JavaScript (ES5, to be precise) doesn't have modules as part of language.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Require.js helps to solve the problem. Instead of referencing hundreds of JavaScript files which expose itself to global namespace, Require.js relies on, so called, Asynchronous Module Definition. The special rules which you code have to follow, to be able to act as module and being loaded by request.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Besides of that, Require.js comes with building/optimization tools, that helps to prepare application to production.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, the Master html has a reference to Require.js main file, which will be responsible for configuration and initialization of app. This typically includes setup of view state management (ViewManager) and routing (Backbone.Router).&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Routing&lt;/h2&gt;    &lt;p&gt;        Router, handles in-browser URL change events and notifies about that changes. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The URL change might appear of 2 things: user clicks some href or submits the form with re-direct. The SPA prevents those things. Instead, all &lt;code&gt;href&lt;/code&gt; click are overloaded, so instead of performing GET request on given URL, JavaScript code would let router know that URL is changing. Router receives the message and using some route rules, call corresponding handler.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The handler job is to load the application and execute it.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Applications&lt;/h2&gt;    &lt;p&gt;        Applications in terms of code, are simple objects with &lt;code&gt;run&lt;/code&gt; (or &lt;code&gt;execute&lt;/code&gt;) function.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The responsibility of application is to fetch all required data and intitialize application Main View. The Main view is then passed to a ViewManager, which is responsible to render it and attach to DOM.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Besides of that, application is also 'logical' group of different modules with one goal. Imagine GMail application again - Contacts, Mails, Tasks are different applications. Each application, could have sub applications (with their own data and views).&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The rule of thumb, one route one application.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;        View Manager&lt;br /&gt;
    &lt;/h2&gt;    &lt;p&gt;        As it's been mentioned about, View Manager is important part of SPA architecture.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It handles the aspects of switching one application (MainView) to another. So, the content of application div is cleared up and than updated with new one. In Backbone.js application, that is particularly important, since besides the DOM update View Manager is responsible to clear up unsubscribe all events that views might be subscribed to, to prevent, so called &lt;a href="http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/"&gt;Zombie View&lt;/a&gt; problem.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Main View and Subviews&lt;/h2&gt;    &lt;p&gt;        Not trivial application could contain some complex UI. All complex UI is being divided on many smaller components.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        MainView is responsible for whole application UI. It's typical job to instantiate and render all required subviews. It also stores the references for all subviews into some internal data structure, so it's been able to close all them, while main view is closed.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;TheMailer - demo application&lt;/h2&gt;    &lt;p&gt;        Here is &lt;a href="https://github.com/alexanderbeletsky/themailer"&gt;TheMailer&lt;/a&gt; - very simple application that implements all the ideas above. I've created that very quickly and I could not call it completed. At the backend it runs ASP.NET MVC/WebAPI and using Require.js + Backbone.js at front end.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It allows you to view and compose email, as well as some simple management of tasks and contacts. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Under the debugger, it is clear how the application is initialized and starting up, how MainView creates Subviews and how Routing and ViewManager works.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        I would call it SPA bare bones. As I mentioned above, using pure Backbone.js is good, since Backbone.js contains all required components which any SPA need (most important it have Backbone.Router).&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        But I would recommended to check further. If you plan stick to Backbone.js, &lt;a href="http://marionettejs.com/"&gt;Backbone.Marionette&lt;/a&gt; by &lt;a href="https://twitter.com/derickbailey"&gt;Derick Beiley&lt;/a&gt; could be really nice option. For Google technologies fans, &lt;a href="http://angularjs.org/"&gt;Angular.JS&lt;/a&gt; makes a lot of sense. For ones that liked &lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn.Micro&lt;/a&gt; during WPF programming, could play with new framework &lt;a href="http://durandaljs.com/"&gt;Durandal.js&lt;/a&gt; by &lt;a href="https://twitter.com/eisenbergeffect"&gt;Rob Eisenberg&lt;/a&gt;.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        SPA is a lot of fun and adventure, welcome in!&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=2PiLNYPLzGI:35jBDPVVMKI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=2PiLNYPLzGI:35jBDPVVMKI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=2PiLNYPLzGI:35jBDPVVMKI:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=2PiLNYPLzGI:35jBDPVVMKI:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/2PiLNYPLzGI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8148951530202025436?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8148951530202025436?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/2PiLNYPLzGI/building-single-pages-applications.html" title="Building Single Pages Applications" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/04/building-single-pages-applications.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0YCSXkzfSp7ImA9WhBVF0U.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-2448003658142693448</id><published>2013-04-24T06:11:00.000+03:00</published><updated>2013-04-24T10:39:28.785+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-24T10:39:28.785+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="Open source" /><category scheme="http://www.blogger.com/atom/ns#" term="Node.js" /><title>Building Single Page Applications with Backbone.js and Express.js</title><content type="html">    &lt;p&gt;This Saturday I was doing my first Backbone.js class. It went really fine, except one fact.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I wanted to show the aspects of creating Single Pages Application running on Backbone. Started the application from scratch, we had to spend a lot of time writing some infrastructure code before we even jump to Backbone. So, after the class I decided to create some boilerplate project, so next time we would just clone it from github and start to work.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;That's how the &lt;a href="https://github.com/alexanderbeletsky/backbone-express-spa"&gt;backbone-express-spa&lt;/a&gt; born.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Backbone.js + Express.js SPA boilerplate&lt;/h2&gt;&lt;p&gt;The project is a &lt;a href="http://expressjs.com/"&gt;Express.js&lt;/a&gt; application using &lt;a href="http://backbonejs.org/"&gt;Backbone.js&lt;/a&gt; as front-end framework. The idea is you just simply clone it, remove non needed routes and application and build something on your own.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I won't put to much details in a blog post, since &lt;a href="https://github.com/alexanderbeletsky/backbone-express-spa"&gt;repo&lt;/a&gt; neat readme section. Just several facts:&lt;br /&gt;
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Minimal and simple&lt;/strong&gt; - pure Backbone code, no plugins. For some real needs plugins are required anyway and you are free to include whatever you want.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMD modules with RequireJS&lt;/strong&gt; - modularity is key factor for large-scale apps, &lt;a href="http://requirejs.org/"&gt;RequireJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concept of Application&lt;/strong&gt; - to group all view, models, collection related to one application unit in one place.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handlebars template&lt;/strong&gt; - using &lt;a href="http://handlebarsjs.com/"&gt;Handlebars&lt;/a&gt; as template engine.&lt;/li&gt;
&lt;/ul&gt;&lt;h2&gt;Further work&lt;/h2&gt;&lt;p&gt;It's not yet completely done. I want to create more meaningful app, show some layouts principles + prepare readme section of building application for production.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I'm also thinking of putting some examples of unit tests both for Express.js and Backbone.js.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Conclusions&lt;/h2&gt;&lt;p&gt;Check the &lt;a href="https://github.com/alexanderbeletsky/backbone-express-spa"&gt;backbone-express-spa&lt;/a&gt; out. If you like it, please give some stars or shout in twitter. I would be really happy to see some pull requests for improving applications or infrastructure. So, if you want to join - you are welcome!&lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=VXW8aA1yYsA:ejdEUz6Y-qo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=VXW8aA1yYsA:ejdEUz6Y-qo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=VXW8aA1yYsA:ejdEUz6Y-qo:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=VXW8aA1yYsA:ejdEUz6Y-qo:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/VXW8aA1yYsA" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/2448003658142693448?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/2448003658142693448?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/VXW8aA1yYsA/building-single-page-applications-with.html" title="Building Single Page Applications with Backbone.js and Express.js" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/04/building-single-page-applications-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4NQ3s8eyp7ImA9WhBVEE8.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-4653083615658017197</id><published>2013-04-14T14:35:00.000+03:00</published><updated>2013-04-15T14:56:32.573+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-15T14:56:32.573+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="E-conomic" /><category scheme="http://www.blogger.com/atom/ns#" term="Mind" /><category scheme="http://www.blogger.com/atom/ns#" term="Conference" /><title>.NET Developer in JavaScript World</title><content type="html">        &lt;p&gt;This is a subscript of lighting talk I did on &lt;a href="http://www.odessajs.org.ua/"&gt;#odessajs&lt;/a&gt; conference that took place 13 April in Odessa.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;The story&lt;/h2&gt;&lt;p&gt;Thinking about the things going on inside and around me I realized - I don't do .NET development more than 1.5 years for now. It's not the &lt;a href="http://www.beletsky.net/2012/07/three-month-without-net-code.html"&gt;first time&lt;/a&gt; I was thinking about that, but now it has a bit different perspective.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;WTH?&lt;/h2&gt;&lt;p&gt;I work in E-conomic company and about 2 years ago we decided to build new product. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Till that time we've learned hard few things: plain jQuery applications is mess, building new shinny product on out-dated infrastructure is bad idea.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;So, we've started with front-end by choosing Backbone.js as our foundation, later on we've decided to switch our API server from .NET to Node.js.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;It appears we got full JavaScript stack on that product and I involved in JavaScript more and more each day.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;I thought I know JavaScript&lt;/h2&gt;&lt;p&gt;That time I mistakenly thought, I can do JS programming. Sure, I understood jQuery selectors, concept of callback and even why we need 'var me = this;' trick in code.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;But the reality was a bit different. Now, listening to podcasts and reading some blogs, I understood that I've been to 'classic' trap on C#/Java developer switching to JavaScript. Languages and frameworks requires time to learn.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Long hard way of learning&lt;/h2&gt;&lt;p&gt;I had to spend the time to learn new stuff. I would say the best source of information was the code written by my &lt;a href="https://github.com/e-conomic?tab=members"&gt;colleagues&lt;/a&gt;. We have great team, so initially I were just reviewing the code following some patterns. I also spent time of peering famous OS projects like underscore and Backbone.js.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;JavaScript  &lt;a href="http://shop.oreilly.com/product/9780596517748.do"&gt;Good Parts&lt;/a&gt;, opened my eyes on few important things as well.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;There are 3 aspects that changed my mind on JavaScript.&lt;br /&gt;
&lt;/p&gt;&lt;h3&gt;JavaScript is dynamic language&lt;/h3&gt;&lt;p&gt;Let's be clear. If someone in 2003 tell me I'm going to program dynamic language and will be happy about, I would never believe that. I was programming C++ and truly believed in types. Types as I was thinking is only way to tackle complexity of software.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Even though, I still think about some advantages of static vs. dynamic languages, my opinion has changed radically.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Dynamic languages are great. I feel I more solve problems rather than designing types (or usually hierarchy of types). Consider that, instead of thinking about the name for next "ProxyAbstractFactoryManager" I'm writing functions that do stuff.&lt;br /&gt;
&lt;/p&gt;&lt;h3&gt;Frictionless development&lt;/h3&gt;&lt;p&gt;I was compiling applications for whole my life. Just to run some simple thing I need to compile and link. It's usually not a problem at all, but depends on project infrastructure it can take a lot of time. Sooner or later you start to hate builds.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;With JavaScript application, you simply should run it. It starting fast so the gap between "write the line of code" and "check the results" became very small.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Instead of heavyweight IDE's I became Sublime Text 2 user. After years in VS you simply could not understand how to write code without IntellySense. But practice shows it's really possible. &lt;br /&gt;
&lt;/p&gt;&lt;h3&gt;Node.js&lt;/h3&gt;&lt;p&gt;To be honest with you, I was very skeptical regarding Node.js initially. But again, practice showed different results. It's been proved that Node.js is very suitable for our product. We are running API server on Node.js and it performs really nice.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Later I started to learn what Node.js platform offers and I was really surprised with it's abilities.&lt;br /&gt;
&lt;p&gt;CommonJS style of writing code started to make sense. Namespacing problem is solved, so you can build big applications there.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I have to add that Node.js is a significant Open Source player. Everything you get by npm is open source, you can check the sources if anything unclear. Most of Node.js modules are hosted in github, so even if you experience issues you can fix it.&lt;br /&gt;
&lt;/p&gt;&lt;script async class="speakerdeck-embed" data-id="8e251d9087200130c2401231381d5999" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"&gt;&lt;/script&gt;&lt;br /&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;&lt;p&gt;JavaScript is awesome. I like the experience of JavaScript programming so far. Whatever you do, front-end or back-end you stay in one "language context". I would not call a huge problem, but usually context switching from one language to another can take something.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Picking up technology for next &lt;a href="http://www.likeastore.com/"&gt;side-project&lt;/a&gt; or quick hack I'm selecting JavaScript.&lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=B_Bmogigphk:EetGSSeSXGM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=B_Bmogigphk:EetGSSeSXGM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=B_Bmogigphk:EetGSSeSXGM:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=B_Bmogigphk:EetGSSeSXGM:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/B_Bmogigphk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/4653083615658017197?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/4653083615658017197?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/B_Bmogigphk/net-developer-in-javascript-world.html" title=".NET Developer in JavaScript World" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/04/net-developer-in-javascript-world.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQMRHw9fCp7ImA9WhBWFkw.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8047523618976678741</id><published>2013-04-10T20:53:00.000+03:00</published><updated>2013-04-10T20:53:05.264+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-10T20:53:05.264+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="BabyStepsBackbone" /><title>Baby steps to Backbone.js: Exploring collections. Part 2.</title><content type="html">    &lt;p&gt;        Backbone.js is event-driven framework. All Backbone entities are extended from &lt;a href="http://backbonejs.org/#Events"&gt;Backbone.Event&lt;/a&gt; object. That means, they are able to raise events, subscribers are able to listen to that events and act accordingly. Let's take a look what type of event does Backbone.Collection have.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Backbone.Collection events&lt;/h2&gt;    &lt;p&gt;        Will have a test suite for that,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('collection events', function () {
    var listener;

    beforeEach(function () {
        collection = new FeedbackCollection();
    });

    beforeEach(function () {
        listener = jasmine.createSpy();
    });
    &lt;/pre&gt;    &lt;p&gt;        Here we are creating collection for testing and Jasmine spy, special function we going to use as event subscriber.&lt;br /&gt;
    &lt;/p&gt;    &lt;h3&gt;Adding element to collection&lt;/h3&gt;    &lt;p&gt;        As we saw &lt;a href="http://www.beletsky.net/2013/03/baby-steps-to-backbonejs-exploring.html"&gt;previously&lt;/a&gt; there are several ways of adding new elements to collection. By add and push methods. The important thing, does not matter what API method you use, Backbone.Collection would trigger 'add' event.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        By &lt;code&gt;add&lt;/code&gt; method,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while adding elements', function () {
    beforeEach(function () {
        collection.on('add', listener);
    });

    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
    });

    it ('should raise add event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    &lt;/pre&gt;    &lt;p&gt;        By &lt;code&gt;push&lt;/code&gt; method,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while pusing elements', function () {
    beforeEach(function () {
        collection.on('add', listener);
    });

    beforeEach(function () {
        collection.push({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
    });

    it ('should raise add event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    &lt;/pre&gt;    &lt;p&gt;        Each event handlers receives model itself and reference to collection.&lt;br /&gt;
    &lt;/p&gt;    &lt;h3&gt;Removing elements from collection&lt;/h3&gt;    &lt;p&gt;        Similarly, there 2 ways of removing items from collection, by remove and pop methods.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        By &lt;code&gt;remove&lt;/code&gt; method,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while removing items', function () {
    beforeEach(function () {
        collection.on('remove', listener);
    });

    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
        var model = collection.get('feedback-1');
        collection.remove(model);
    });

    it ('should raise remove event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    &lt;/pre&gt;    &lt;p&gt;        By &lt;code&gt;pop&lt;/code&gt; method,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while poping items', function () {
    beforeEach(function () {
        collection.on('remove', listener);
    });

    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
        collection.pop();
    });

    it ('should raise remove event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    &lt;/pre&gt;    &lt;h3&gt;Resetting and sorting&lt;/h3&gt;    &lt;p&gt;        Besides just adding and removing stuff from collection, it have few more method which reaction is triggering event. It's reset and sort. Reset is the bulk insert into collection, it works great when we fetch some data from server and want to push everything just by one operation. Sort, is rarely called manually, since if collection provides &lt;code&gt;comparator&lt;/code&gt; function, it would sort itself, during add or reset operations. But sometimes sorting could be triggered from UI as user changes the sort column of table, for example.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Resetting collection,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while reseting collection', function () {
    beforeEach(function () {
        collection.on('reset', listener);
    });

    beforeEach(function () {
        collection.reset([
            {id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}]);
    });

    it('should raise reset event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
&lt;/pre&gt;    &lt;p&gt;        Sorting collection,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while sorting collection', function () {
    beforeEach(function () {
        collection.on('sort', listener);
    });

    beforeEach(function () {
        collection.reset([
            {id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}]);
        collection.sort();
    });

    it('should raise sort event', function () {
        expect(listener).toHaveBeenCalled();
    });
});
    &lt;/pre&gt;    &lt;h2&gt;Why it matters?&lt;/h2&gt;    &lt;p&gt;        Knowing the events of all Backbone.js entities is very important. You should always design you application based on events triggering/subscription, instead of direct function call. That would make your code much de-coupled and UI logic very flexible.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=xehGSdgJP7k:TWyszS3C3Fs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=xehGSdgJP7k:TWyszS3C3Fs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=xehGSdgJP7k:TWyszS3C3Fs:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=xehGSdgJP7k:TWyszS3C3Fs:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/xehGSdgJP7k" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8047523618976678741?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8047523618976678741?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/xehGSdgJP7k/baby-steps-to-backbonejs-exploring.html" title="Baby steps to Backbone.js: Exploring collections. Part 2." /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/04/baby-steps-to-backbonejs-exploring.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YASH48fCp7ImA9WhBXF0k.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-7217113663976571388</id><published>2013-03-31T18:52:00.000+03:00</published><updated>2013-03-31T18:52:29.074+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-31T18:52:29.074+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Applications" /><category scheme="http://www.blogger.com/atom/ns#" term="Hackatone" /><category scheme="http://www.blogger.com/atom/ns#" term="Social" /><title>Likeastore, Application Built on Hackathone</title><content type="html">    &lt;p&gt;        It's my &lt;a href="http://www.beletsky.net/2011/06/hackatone-in-kiev-11-12-june.html"&gt;second time&lt;/a&gt; I attended hackatone. As last time, it took place in Ciklum, the best office in Kiev, so I had very strong wish to visit it. My previous experience showed several things: hacktone is absolutely unpredicable thing, you can't guess which projects will be popular or not.. and the second, that it's hard to do something valuable alone.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, this time I decided to build a team of guys I know and trust, so we can do something together. Those two guys appeared to be my colleagues, in @debitoor project &lt;a href="https://github.com/voronianski"&gt;@voronianski&lt;/a&gt; and &lt;a href="https://github.com/mamant"&gt;@mamant&lt;/a&gt;. We gathered together, to build a product which was called - "Likeastore"&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Idea behind&lt;/h2&gt;    &lt;p&gt;        All of us having at least those 3 accounts: facebook, twitter and github. And all of those are continuous stream of information. If you have an interesting network, it probably produces interesting content so you do much of likes/favorites/stars (stories, tweets, or interesting gihub repos). The problem, it's very difficult to keep this information ordered - you typically remember you heard something interesting, but could not remember the source of it.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        "Likeastore" is aimed to fix this problem. Integrating wish different services it's keeping your "likes" information in good order, with nice search and smart categorizing.&lt;br /&gt;
    &lt;/p&gt;    &lt;img src="https://lh5.googleusercontent.com/-AaH9Nrnr54o/UVhZihO3yjI/AAAAAAAAR1Y/FhtHcOksuik/s988/login.png" style="width: 620px" alt="likeastore login screen"/&gt;&lt;br /&gt;
    &lt;h2&gt;What we did?&lt;/h2&gt;    &lt;p&gt;        We basically allow "Likeastore" to connect all those application by their open API and collect the information from it. We transform the information into something generic and grouping it together. So, the users are having all information up-to-date in nice and clear dashboard.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Originally we had ambition to have a kinda real-time. In the way, I favorited the tweet and "Likeastore" almost immediately got the information. We had to drop it. The reason is API's of popular applications are very quoted. You simply cannot do more request that in quota, otherwise you just banned.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, nethertheless of similar projects, we don't want to make next social network of bookmarks. Instead, we want to build easy to use and powerful information keeper. Something, that help you to have things in order.&lt;br /&gt;
    &lt;/p&gt;    &lt;img src="https://lh4.googleusercontent.com/-cHk7Pdbyus8/UVhZisS6e5I/AAAAAAAAR1g/-3uXVV28rL0/s988/setup.png" style="width: 620px" alt="likeastore setup screen"/&gt;&lt;br /&gt;
    &lt;h2&gt;How we did it?&lt;/h2&gt;    &lt;p&gt;        In fact, we've build a "thrown-out" prototype. The &lt;a href="https://github.com/organizations/likeastore"&gt;code&lt;/a&gt; is a shitty inside, so we bit far of nearest production. But, we've created an interesting application. We split on 2 + 1, two backend (me and &lt;a href="https://github.com/voronianski"&gt;@voronianski&lt;/a&gt;) and one front-end guy (&lt;a href="https://github.com/mamant"&gt;@mamant&lt;/a&gt;). Sat closely and worked shoulder-to-shoulder for next 22 hours. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        From the very beginning I had very clear vision of stuff we need to do. I could imagine architecture and UI principles. And as soon I shared that the teammates accepted that really fine and provided high quality feedback and collaboration. That helped us to have a strong team in my perspective.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        All of us are JS developers, so no doubt we've taken a JavaScript stack as default. Node.js, powered by Express.js at the backend and Backbone.js front end. Sometimes it's tricky, but in fact - it's powerful combination. &lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;A bit of tech info&lt;/h2&gt;    &lt;p&gt;        We are having 2 main architectural units: core and connectors. Core, is Express.js application having both serving static content and providing API. The API itself, consists on public and private parts. Public part is aimed our web client (or potentiall apps), where the private is used to communicated connectors.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Connectors are just very simple HTTP services, which perform the handshake with core and then post back all data they have collected through API's. That means, we have 3 connectors now - twitter, github and facebook. Facebook, became a quite difficult to integrated with, so we currently dropped it.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        We are having &lt;a href="http://couchdb.apache.org/"&gt;CouchDB&lt;/a&gt; as our storage. We took it, because &lt;a href="https://github.com/voronianski"&gt;@voronianski&lt;/a&gt; had some good experience with. That appeared to be a very lucky decision. CouchDB is very interesting NoSQL solution. It's storage model has few interesting features. One of them is "merge-update". Means, you can post exactly same set of information many times, but CouchDB would not create new entities. It would merge identical documents into one. That simplied connectors very much, since they no longer need to track only new information, but could post back just a transformed bulk of information from API's.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Initially, we all agreed - our UI will never be default Bootstrap theme. It's overused and impress no more as toilet door. That's where &lt;a href="https://github.com/mamant"&gt;@mamant&lt;/a&gt; apply his best skills. He carefully worked all our screens making a it look nice and original. &lt;br /&gt;
    &lt;/p&gt;    &lt;img src="https://lh3.googleusercontent.com/-XSXpDhEuX9Y/UVhZjLe7w6I/AAAAAAAAR1k/HI6xIJQnUXc/s988/dashboard.png" style="width: 620px" alt="likeastore dashboard screen"/&gt;&lt;br /&gt;
    &lt;h2&gt;Presentation and feedback&lt;/h2&gt;    &lt;p&gt;        Without few features we did demo-able version in time. We have concluded few major fixes, just before the deadline. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I did a presentation of app in short way, without anything unimportant (at least I wish to think so) and we had received great feedback. People liked the idea, so we've collected 32 voices that brought us 2nd place.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        That gives a much of inspiration for further work! All of us are very enthusiastic to make the stuff done. It's a lot of work, actually.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I just want to say thank you to all organizers of this event, it was nicely handled. And to the team, for making it fun and interesting.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Stay tuned for release of "Likeastore", check out &lt;a href="https://github.com/likeastore"&gt;sources&lt;/a&gt; in a meanwhile.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=cfHJL-YtzM8:_UikAFdZpmo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=cfHJL-YtzM8:_UikAFdZpmo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=cfHJL-YtzM8:_UikAFdZpmo:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=cfHJL-YtzM8:_UikAFdZpmo:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/cfHJL-YtzM8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7217113663976571388?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7217113663976571388?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/cfHJL-YtzM8/likeastore-application-built-on.html" title="Likeastore, Application Built on Hackathone" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/-AaH9Nrnr54o/UVhZihO3yjI/AAAAAAAAR1Y/FhtHcOksuik/s72-c/login.png" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2013/03/likeastore-application-built-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MCQX08fyp7ImA9WhBXE0Q.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-2172856731143637804</id><published>2013-03-27T17:51:00.000+02:00</published><updated>2013-03-27T17:51:00.377+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-27T17:51:00.377+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="BabyStepsBackbone" /><title>Baby steps to Backbone.js: Exploring collections</title><content type="html">    &lt;p&gt;        After initial introduction to Backbone's &lt;a href="http://www.beletsky.net/2012/12/baby-steps-to-backbonejs-unit-testing.html"&gt;views&lt;/a&gt; and &lt;a href="http://www.beletsky.net/2012/11/baby-steps-to-backbonejs-unit-testing.html"&gt;models&lt;/a&gt;, we going to look on next Backbone.js fundamental entity - &lt;a href="http://backbonejs.org/#Collection"&gt;Collection&lt;/a&gt;. Collections represents the ordered set of models and became very handy for any type of applications. Consider that, we almost always operate with set of different models: posts, tweets, news etc. all of that are collections, typically rendered as lists or grids.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        In small application we are doing through that series we have collection of feedbacks. But before I show how to integrate collection into the app, I want to make sure you understand all collection properties right. We'll do that by TDD'ing the collection and exploring it's behavior.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Collection construction&lt;/h2&gt;    &lt;p&gt;        So, to create collection we need to extend &lt;code&gt;Backbone.Collection&lt;/code&gt; object,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var FeedbackCollection = Backbone.Collection.extend({
    model: Feedback,
    url: '/feedback'
});
    &lt;/pre&gt;    &lt;p&gt;        Here we just specified the URL for collection persistence and the model, of which the collection would consists of. Let's prepare the test suite for collection stories,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('FeedbackCollection.js spec', function () {
    var collection;
});
    &lt;/pre&gt;    &lt;p&gt;        And create our first specification,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('when constructing', function () {
    describe('just empty', function () {
        beforeEach(function () {
            collection = new FeedbackCollection();
        });

        it('should be created', function () {
            expect(collection).toBeDefined();
        });
    });
&lt;/pre&gt;    &lt;p&gt;        Just to make sure, our definition is fine and we are able to instantiate new collection object.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        &lt;code&gt;FeedbackCollection&lt;/code&gt; constructor have few optional arguments - &lt;code&gt;models&lt;/code&gt;, &lt;code&gt;options&lt;/code&gt;. Models, could be either arrays of objects, or array of Backbone.Models. In case of object, collection constructor would "turn" them to models (taking the type we specified on collection definition) and add those models to collection. &lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('with objects', function () {
    beforeEach(function () {
        var models = [
            {email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {email: 'b@b.com', website: 'b.com', feedback: 'good bye'}
        ];
        collection = new FeedbackCollection(models);
    });

    it('should be lenght of 2', function () {
        expect(collection.length).toBe(2);
    });

    it('should contain models inside', function () {
        expect(collection.models).toBeDefined();
    });
});
&lt;/pre&gt;    &lt;p&gt;        or,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('with models', function () {
    beforeEach(function () {
        var models = [
            new Feedback({email: 'a@a.com', website: 'a.com', feedback: 'hello'}),
            new Feedback({email: 'b@b.com', website: 'b.com', feedback: 'good bye'})
        ];
        collection = new FeedbackCollection(models);
    });

    it('should be lenght of 2', function () {
        expect(collection.length).toBe(2);
    });

    it('should contain models inside', function () {
        expect(collection.models).toBeDefined();
    });
});
&lt;/pre&gt;    &lt;p&gt;        Both things are equivalent. Moreover, typically it's only unit tests you need to initialize collections that way, so I usually prefer first option.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The &lt;code&gt;options&lt;/code&gt; parameter, could contain the type of model that collection contain. So, if collection does not specify &lt;code&gt;model&lt;/code&gt; property, &lt;code&gt;Backbone.Model&lt;/code&gt; will be created by default.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('with options', function () {
    beforeEach(function () {
        var models = [
            {email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {email: 'b@b.com', website: 'b.com', feedback: 'good bye'}
        ];
        collection = new Backbone.Collection(models);   // not specifying model
    });

    it('should be created', function () {
        expect(collection).toBeDefined();
    });

    it('should have models of Backbone.Model type', function () {
        expect(collection.models[0].constructor).toBe(Backbone.Model);
    });
&lt;/pre&gt;    &lt;p&gt;        You can override that by passing &lt;code&gt;{model: MyModel}&lt;/code&gt; options object,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('while passing model option', function () {
    beforeEach(function () {
        var models = [
            {email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {email: 'b@b.com', website: 'b.com', feedback: 'good bye'}
        ];
        collection = new Backbone.Collection(models, { model: Feedback });
    });

    it('should have models of Feedback type', function () {
        expect(collection.models[0].constructor).toBe(Feedback);
    });
});
&lt;/pre&gt;    &lt;p&gt;        Despite of that possibility I really rare use that in practice. It's better to simply specify model type in collection definition, that makes code easy to understand.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Accessing collection elements&lt;/h2&gt;    &lt;p&gt;        After collection has been constructed, it's possible to access internal models. There are several ways of doing that.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The simplest one is by index,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('when accessing collection elements', function () {
    var first, second, models;

    describe('by index', function () {
        beforeEach(function () {
            models = [
                {email: 'a@a.com', website: 'a.com', feedback: 'hello'},
                {email: 'b@b.com', website: 'b.com', feedback: 'good bye'}
            ];
            collection = new FeedbackCollection(models);
        });

        beforeEach(function () {
            first = collection.at(0);
            second = collection.at(1);
        });

        it('should get first model by index', function () {
            expect(first.toJSON()).toEqual(models[0]);
        });

        it('should get second model by index', function () {
            expect(second.toJSON()).toEqual(models[1]);
        });
    });
&lt;/pre&gt;    &lt;p&gt;        Even it possible, in real apps you probably don't know the index of model you need to get from collection, since they might come from server in unpredictable order. So, instead of index, getting by id is more appropriate way.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('by id', function () {
    beforeEach(function () {
        models = [
            {id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}
        ];
        collection = new FeedbackCollection(models);
    });

    beforeEach(function () {
        first = collection.get('feedback-1');
        second = collection.get('feedback-2');
    });

    it('should get first model by id', function () {
        expect(first.toJSON()).toEqual(models[0]);
    });

    it('should get second model by id', function () {
        expect(second.toJSON()).toEqual(models[1]);
    });
});
&lt;/pre&gt;    &lt;p&gt;        And finally, something that I being trapped many time while starting up with Backbone - indexers on collection, does not work.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('indexer does not work', function () {
    beforeEach(function () {
        models = [
            {id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'},
            {id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}
        ];
        collection = new FeedbackCollection(models);
    });

    it('should be undefined', function () {
        expect(collection[0]).not.toBeDefined();
    });
});
&lt;/pre&gt;    &lt;h2&gt;Adding and removing items&lt;/h2&gt;    &lt;p&gt;        Next, we need to understand to how to add and remove items from collections.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        There are 2 ways of adding item into backbone collection: &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;. They are very similar, but there are difference between those. The add method takes a model or array of models and the options you can specify the position there the item should be interred to. Push method, would simply add new item to the end of collection.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('by add method', function () {
    beforeEach(function () {
        collection.add({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
    });

    it('should be added', function () {
        expect(collection.get('feedback-1')).toBeDefined();
    });

    it('should be converted to model', function () {
        expect(collection.get('feedback-1').constructor).toBe(Feedback);
    });

    describe('with index specified', function () {
        beforeEach(function () {
            collection.add({id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'}, {at: 0});
        });

        it('should have 2 items in collection', function () {
            expect(collection.length).toBe(2);
        });

        it('should have feedback-2 item at index 0', function () {
            expect(collection.at(0).id).toBe('feedback-2');
        });
    });
});
&lt;/pre&gt;    &lt;p&gt;        By push,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('by push method', function () {
    beforeEach(function () {
        collection.push({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
    });

    it('should be added', function () {
        expect(collection.get('feedback-1')).toBeDefined();
    });

    it('should be converted to model', function () {
        expect(collection.get('feedback-1').constructor).toBe(Feedback);
    });

    describe('with next push', function () {
        beforeEach(function () {
            collection.push({id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'});
        });

        it('should have 2 items in collection', function () {
            expect(collection.length).toBe(2);
        });

        it('should have feedback-1 item at index 0', function () {
            expect(collection.at(0).id).toBe('feedback-1');
        });
    });
});
&lt;/pre&gt;    &lt;p&gt;        Please note, that &lt;code&gt;push&lt;/code&gt; recieves the same options as &lt;code&gt;add&lt;/code&gt;, but it's just a short-cut for &lt;code&gt;add&lt;/code&gt; method (take a look how it's &lt;a href="https://github.com/documentcloud/backbone/blob/master/backbone.js#L747"&gt;implemented&lt;/a&gt;, to make it completely clear)&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        For removing the items, we also have 2 methods: &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;pop&lt;/code&gt;. They are opposite symmetrical to the &lt;code&gt;add&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt;. Remove, removes specified model from collection, pop removes the last model in collection. This is shown by following specification,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;describe('when removing items', function () {
    beforeEach(function () {
        collection = new FeedbackCollection();
    });

    beforeEach(function () {
        collection.push({id: 'feedback-1', email: 'a@a.com', website: 'a.com', feedback: 'hello'});
        collection.push({id: 'feedback-2', email: 'b@b.com', website: 'b.com', feedback: 'good bye'});
    });

    describe('by remove method', function () {
        beforeEach(function () {
            var model = collection.get('feedback-1');
            collection.remove(model);
        });

        it('should be removed', function () {
            expect(collection.get('feedback-1')).not.toBeDefined();
        });
    });

    describe('by pop method', function () {
        beforeEach(function () {
            collection.pop();
        });

        it('should be removed', function () {
            expect(collection.get('feedback-2')).not.toBeDefined();
        });
    });
});
&lt;/pre&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        We've just gone for a very basic features of Backbone.Collection type. Next time, we'll explore more about collections as events it produces, fetching and persisting data to server.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=we96K5OJIBk:lr1hjNWvhZA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=we96K5OJIBk:lr1hjNWvhZA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=we96K5OJIBk:lr1hjNWvhZA:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=we96K5OJIBk:lr1hjNWvhZA:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/we96K5OJIBk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/2172856731143637804?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/2172856731143637804?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/we96K5OJIBk/baby-steps-to-backbonejs-exploring.html" title="Baby steps to Backbone.js: Exploring collections" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/03/baby-steps-to-backbonejs-exploring.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QNQXw4cSp7ImA9WhBQEUQ.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8753941241727088890</id><published>2013-03-13T20:29:00.001+02:00</published><updated>2013-03-13T20:29:50.239+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-13T20:29:50.239+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="E-conomic" /><category scheme="http://www.blogger.com/atom/ns#" term="Life" /><title>Third Year of E-conomic</title><content type="html">&lt;p&gt;That's my traditional post on yet another anniversary in &lt;a href="http://www.e-conomic.com/"&gt;E-conomic&lt;/a&gt; company. Even thought, I still work there, this year I've heard a bit less of &lt;a href="http://www.e-conomic.com/"&gt;E-conomic&lt;/a&gt; but more about &lt;a href="https://debitoor.com/"&gt;Debitoor&lt;/a&gt; instead. Debitoor is very cool product me and &lt;a href="https://debitoor.com/about/the-team"&gt;my team&lt;/a&gt; is working on and I was totally focused on that during this year.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, what's interesting about? Alright, it begins with &lt;a href="http://www.e-conomic.com/"&gt;E-conomic&lt;/a&gt; company, which through about 10 years on market gathered huge experience in online accounting. The primary target audience for all that years were professional accounters and administrators that have pretty solid knowledge what the accounting is. But due influence of internet economy and small-business grow there appeared high demand on simple accounting software, that could be easily understood even for non-professional accounters. That's were we saw the opportunity. That's then the &lt;a href="https://debitoor.com/"&gt;Debitoor&lt;/a&gt; born.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Technologically it's been very innovative for us, too. As I &lt;a href="http://www.beletsky.net/2012/03/second-year-of-e-conomic.html"&gt;wrote&lt;/a&gt; last year, the March was the month we tried how good different technologies might work for us. The decision were taking up to full JavaScript stack - &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; and &lt;a href="http://www.mongodb.org/"&gt;MongoDB&lt;/a&gt; as backend, &lt;a href="http://backbonejs.org/"&gt;Backbone.js&lt;/a&gt; as front end technologies.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, near the April we have a working product running .NET + MSSQL, that was on production and customers started to use, we decided to switch backend from .NET to Node.js. The HTTP API interfaces were "copied" from ASP.NET MVC implementation to exactly the same but on Express.js. The difference was in the way how ASP.NET MVC and Express.js is serving the HTML responses, so we have to re-desing the way how front-end application is being initialized and started. Since the low coupling of our front end to ASP.NET features, the rest of Backbone.js application remained absolutely the same.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        All existing data has been exported to JSON files and been imported to MongoDB through the existing API. That gave us a chance to make some performance measuring and we definitely we happy about. Average HTTP request were handled in ~100ms that was a quite big boost comparing to previous platform.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Front-end is being involved as well. We've been switched to Single Page Application (SPA) architecture client side and there is no way back. With Node.js backend we easily moved application to cloud, all static resources to CloudFront that affected initial load time as a result made application to look and feel incredibly fast.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        But the most important is - users love it! We've got plenty of sign-ups during the day, from different countries as Germany, Spain, Great Britain, Columbia etc., recently we've started premium campaign, and the premium users joins us. UI/UX are tweeked all the time, based on future application vision and A/B tests.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        All that makes me feel - your work is important and you do something valuable.. and that is exactly what keeps me working on &lt;a href="http://www.e-conomic.com/"&gt;E-conomic&lt;/a&gt;. It's interesting and make sense - that's all I need.        &lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=OHizrKLTbfw:S0iepbyjYZU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=OHizrKLTbfw:S0iepbyjYZU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=OHizrKLTbfw:S0iepbyjYZU:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=OHizrKLTbfw:S0iepbyjYZU:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/OHizrKLTbfw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8753941241727088890?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8753941241727088890?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/OHizrKLTbfw/third-year-of-e-conomic.html" title="Third Year of E-conomic" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/03/third-year-of-e-conomic.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IERn05cSp7ImA9WhNUE0Q.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-5645594183889698088</id><published>2013-01-05T17:25:00.001+02:00</published><updated>2013-01-05T17:25:07.329+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-01-05T17:25:07.329+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Retrospective" /><title>Looking back to 2012</title><content type="html">    &lt;p&gt;        It's the first Saturday of New Year, so it would be good idea to spend some time thinking of year that passed.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Work in e-conomic&lt;/h2&gt;    &lt;p&gt;        That was yet another great year in e-conomic. We have build great app - &lt;a href="https://debitoor.com/"&gt;Debitoor&lt;/a&gt;. Along the way, we were trying different approaches, re-writing things from scratch, designing and re-designing again and again. Finally we got very solid application built upon Node.js, MongoDB and Backbone.js. Debitoor has been created with scalability in mind, we started with Heroku cloud service, eventually moved to Amazon EC for back-end and Amazon Cloud Front for front-end. Now, it's working amazingly fast and for 8 month we gathered ~20,000 signups, launched service for many countries.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        At the beginning of the year we were a bunch of .NET developers diving into JavaScript. Having a very strong team of responsible professionals we've gathered initial knowledge quite fast. I've been focused almost at front-end this year. You probably noticed that I slowed down my writings about &lt;a href="http://www.beletsky.net/search/label/asp.net"&gt;ASP.NET MVC&lt;/a&gt; and doing more for &lt;a href="http://www.beletsky.net/search/label/Backbone.js"&gt;Backbone.js&lt;/a&gt;. That just reflects the fact of my current specialization. Initially, I was not very serious about Node.js platform. But with time, I became to love it. It speed up our development velocity several times, the API we've built on this platform shows amazing performance indicators.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The team has been expanded a bit. We got new very strong PO and few developers both in Ukraine and Denmark and all of those guys are awesome. I enjoy friendly and cooperative environment we have in team. Besides of that, this year we got 2 QA guys. QA influenced the development really much and helped to improve overall quality of service. I would also mention amazing UX team we have, calling themselves "UX Wizards Team" I have to admit - we are really doing magically things. UI/UX of app is changing all the time and with each iteration it became more intuitive, comprehensive and good looking.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Speaking and blogging&lt;/h2&gt;    &lt;p&gt;        For 2012 and have written 63 blog posts on various topics, primarily on .NET, JavaScript and TDD. Some stats, from Google Analytics:&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I don't track GA stats actively and I was really surprised to see the figures. I got 105,490 visits, 79,445 unique visits. That gives 288% more traffic than &lt;a href="http://www.beletsky.net/2011/12/retrospective-2011.html"&gt;2011&lt;/a&gt;. That's quite big number and I could only hope that this year the traffic would only grow up.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        As for most viewed blog posts:&lt;br /&gt;
    &lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;&lt;a href="http://www.beletsky.net/2012/04/new-in-aspnet-mvc4-razor-changes.html"&gt;New in ASP.NET MVC4: Razor changes&lt;/a&gt; where I highlighted some new stuff of ASP.NET MVC 4 and it's been tweeted by &lt;a href="http://weblogs.asp.net/scottgu/"&gt;@scottgu&lt;/a&gt; (what explains it's popularity).&lt;/li&gt;
        &lt;li&gt;&lt;a href="http://www.beletsky.net/2012/02/new-tools-in-my-tdd-arsenal.html"&gt;New Tools in My TDD Arsenal&lt;/a&gt; I posted about stuff I used in .NET development like NCrunch, NSubstitute and FluentAssertions.&lt;br /&gt;
        &lt;/li&gt;
        &lt;li&gt;&lt;a href="http://www.beletsky.net/2012/06/starting-up-nodejs-development-on.html"&gt;Starting Up Node.js Development on Windows&lt;/a&gt; as quick introduction to setup Node.js development environment on Windows box.&lt;/li&gt;
    &lt;/ul&gt;    &lt;p&gt;        Something that I personally liked the most:&lt;br /&gt;
    &lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;&lt;a href="http://www.beletsky.net/2012/01/convention-based-ioc-configuration.html"&gt;Convention based IoC configuration&lt;/a&gt; convention over configuration principles applied to IoC.&lt;/li&gt;
        &lt;li&gt;&lt;a href="http://www.beletsky.net/2012/06/7-weeks-with-python.html"&gt;7 Weeks With Python&lt;/a&gt; my little journey with Python language during Audacity CS101 course.&lt;/li&gt;
        &lt;li&gt;&lt;a href="http://www.beletsky.net/2012/08/developing-web-applications-faster.html"&gt;Developing Web Applications Faster&lt;/a&gt; that shows how to apply LiveReload technique to working faster with front-end tasks.&lt;br /&gt;
        &lt;/li&gt;
    &lt;/ul&gt;    &lt;p&gt;        As I said above my focus moved from .NET to JavaScript a bit. I've started a series of blog posts called &lt;a href="http://www.beletsky.net/search/label/BabyStepsBackbone"&gt;Baby steps to Backbone.js&lt;/a&gt;, I'm learning JavaScript and other front-end frameworks, so I would say more info about JavaScript to come.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        As for speaking, I've prepared 10 &lt;a href="https://speakerdeck.com/alexanderbeletsky"&gt;presentations&lt;/a&gt; during 2012 and had nearly 15 speeches on different events. That's not a lot, but it's much more that 2011 and I feel good about it.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Trainings and Consulting&lt;/h2&gt;    &lt;p&gt;        Our &lt;a href="http://xpinjection.com/trainings/tdd-in-net/"&gt;TDD in .NET&lt;/a&gt; training became very popular. We did a quite of the through the year. It goes very fine and thanks to &lt;a href="http://xpinjection.com/"&gt;XP Injection&lt;/a&gt; efforts I could only predict more to come. I also did a training on &lt;a href=""&gt;ASP.NET MVC&lt;/a&gt; which went quite fine, but very small demand could be seen on that. I hope that 2013 will bring some more trainings in JavaScript as well.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        In 2012 I've tried myself as a consultant. I've been contacted by the guy who listened to my &lt;a href="https://speakerdeck.com/alexanderbeletsky/large-scale-javascript-applications"&gt;JavaScript talk&lt;/a&gt; and asked to help with architectural advices on new service he tries to build. I think that was very good experience for both of us. Of cause, that's just a tiny job but I hope that consulting could work for me in future.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I believe that 2012 was just the beginning of Trainings &amp; Consulting part of my duties and 2013 will be the one to prove it.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Communities&lt;/h2&gt;    &lt;p&gt;        &lt;a href="http://www.facebook.com/groups/574355212591240/"&gt;Kyiv Beer'N'Code&lt;/a&gt; is something that I personally happy about. Being relauched in September 2012, we haven't missed any meet up. Taking into account it's bi-weekly meetings that's a lot. New guys, who joined the group are open minded and smart, so it's always interesting to spend time there. I would like to have say big thanks to &lt;a href=""&gt;Ciklum&lt;/a&gt; company, who provides a support for us.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        &lt;a href="http://xpinjection.com/uadevclub/"&gt;UA Dev Club&lt;/a&gt; is growing and growing. Each meeting gathers more and people and it's great. I did a few talks there I try to attend as more meetings as I can (even if they are talking about Java). UA Dev Club became very active this year and I wish it only improves in 2013.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        &lt;a href="http://kievalt.net/"&gt;Kiev ALT.NET&lt;/a&gt; in opposite a little slowed down this year. Primarily, because it's leader moved to another city, so it became difficult to manage the stuff. Nevertheless, we've organized very cool meetup at the end of year with Jimmy Bogard and it motivated us to go on. We already have planned few meetings ahead and expecting more interesting foreign guests to come. Besides of that, &lt;a href="http://www.jetbrains.com/"&gt;JetBrains&lt;/a&gt; might be the one who can help us this year.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Side projects&lt;/h2&gt;    &lt;p&gt;        The last topic in my list that makes me a bit sad. I have to admit, I haven't produced anything really noticeable through the year. My problem is that I'm starting few projects and none of them could make done. Simply lacking the energy and motivation to accomplish it. I believe that "Less is more" should be my slogan for 2013.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Some new projects appeared in my github profile in 2012:&lt;br /&gt;
    &lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/wonka"&gt;Wonka&lt;/a&gt; - supposed to be a blogging engine based on github with easy integration to ASP.NET MVC applications. I had some designs and ideas of implementing it, but it's still in very early stage.&lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/aspnet.mobile"&gt;ASP.NET Mobile&lt;/a&gt; - small project that I've completed during preparation to the conference. It launched on AppHabor at &lt;a href="http://aspnetmobile.apphb.com/"&gt;http://aspnetmobile.apphb.com/&lt;/a&gt;, but the traffic is very low there.&lt;br /&gt;
        &lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/foundstyles"&gt;FoundStyles&lt;/a&gt; - while my playing with Foundation framework I've decided to build small site to keep gallery of themes there, so &lt;a href="http://foundstyles.com/"&gt;http://foundstyles.com/&lt;/a&gt; was born. I've created only 3 and after left it. But, currently it has about 300 visits per day and it make sense to update the project. It would be easier, since Foundation moved to SASS.&lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/freeze"&gt;Freeze&lt;/a&gt; - small utility project to make a snapshots of dynamic web sites. Originally I've created it to make a snapshot of Kyiv Beer &amp;&amp; Code site and place it to github. I've spent some time on that and it's not yet done (as well as Kyiv Beer &amp;&amp; Code site is not moved).&lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/github-fs.net"&gt;GithubFS.net&lt;/a&gt; - using Github remote repository as local file system project. It's on really early development stage, but has some documentation describing ideas. And, it's not done as well.&lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/benchmark-js"&gt;Benchmark-js&lt;/a&gt; - tiny library for measuring JS execution time and putting that to log. Works both Node.js and browser.&lt;/li&gt;
        &lt;li&gt;&lt;a href="https://github.com/alexanderbeletsky/backbone.computedfields"&gt;Backbone Computed.Fields&lt;/a&gt; - something that I personally happy with. Started as some code I've created for debitoor it moved as stand alone Backbone.js plugin.&lt;/li&gt;
    &lt;/ul&gt;    &lt;p&gt;        If you reading this and those projects looks interesting to you, so you would like to pick that up - please let me know.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Something that I has started in 2011 and feel most shame for is &lt;a href="https://github.com/alexanderbeletsky/candidate"&gt;Candidate&lt;/a&gt;. Being &lt;a href="http://www.beletsky.net/2012/08/re-thinking-candidate-application.html"&gt;restarted&lt;/a&gt; this year I had big ambitions to actually make it done. I still want to implement some meaningful product for .NET web applications deployment. And Candidate would probably be my focus at the beginning of 2013.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        Despite of side-projects failure, 2012 was a good year. 2013 is the year of Python that means it would bring happy coding time for all the developers. Happy New Year!&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=2POLStmUKvM:pUefmELZI0s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=2POLStmUKvM:pUefmELZI0s:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=2POLStmUKvM:pUefmELZI0s:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=2POLStmUKvM:pUefmELZI0s:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/2POLStmUKvM" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/5645594183889698088?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/5645594183889698088?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/2POLStmUKvM/looking-back-to-2012.html" title="Looking back to 2012" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2013/01/looking-back-to-2012.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQERn0yfyp7ImA9WhNVFEs.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-4999385368740423358</id><published>2012-12-25T22:28:00.000+02:00</published><updated>2012-12-25T22:28:27.397+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-25T22:28:27.397+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><title>Introducing Backbone.ComputedFields</title><content type="html">    &lt;p&gt;        Recently, I've been working on small project which I want to share here. It's called &lt;a href="https://github.com/alexanderbeletsky/backbone.computedfields"&gt;Backbone.ComputedFields&lt;/a&gt; and it's small plugin that extends Backbone.Model functionality a bit.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I needed to have a model with 'virtual' fields. Namely, fields that does not belong to model directly, but being computed based on some other fields values.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The easiest solution would be simply introduce some model methods, say &lt;code&gt;model.getComputedField() / model.setComputedField()&lt;/code&gt; and store the value inside the model object. But that turns out to be bad idea, for several reasons. First, we are breaking usual Backbone interface for getting and setting values - &lt;code&gt;model.get('computed') / model.set('computed', 100)&lt;/code&gt;. Also, if model is binded to a view, we are responsible for raising events manually, in case of computed or depended field changing.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, after few iterations &lt;a href="https://github.com/alexanderbeletsky/backbone.computedfields"&gt;Backbone.ComputedFields&lt;/a&gt; was born. The design goals: to be simple, to be declarative, to be friendly to model binding (read, respect the events).&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Use cases&lt;/h2&gt;    &lt;p&gt;        Typical use cases for &lt;a href="https://github.com/alexanderbeletsky/backbone.computedfields"&gt;Backbone.ComputedFields&lt;/a&gt; are: calculating the prices; concatenating several fields; encapsulating the logic of retrieving object by reference.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It's fairly important, that computed field could change. Based on it's value, dependent fields should be updated.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Examples&lt;/h2&gt;    &lt;p&gt;        Let's take a look on few examples. The models here are very simplified. But, it shows the main application of &lt;a href="https://github.com/alexanderbeletsky/backbone.computedfields"&gt;Backbone.ComputedFields&lt;/a&gt;.&lt;br /&gt;
    &lt;/p&gt;    &lt;h3&gt;Calculating prices&lt;/h3&gt;    &lt;p&gt;        The model represents the product, which contains net price and VAT rate.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var Produc = Backbone.Model.extend({
    initialize: function () {
        this.computedFields = new Backbone.ComputedFields(this);
    },

    computed: {
        grossPrice: {
            depends: ['netPrice', 'vatRate'],
            get: function (fields) {
                return fields.netPrice * (1 + fields.vatRate / 100);
            },
            set: function (value, fields) {
                fields.netPrice = value / (1 + fields.vatRate / 100);
            }
        }
    }
});
&lt;/pre&gt;    &lt;p&gt;        So, we have &lt;code&gt;grossPrice&lt;/code&gt; as computed field. That field depends on 'netPrice' and 'vatRate' and being calculated by simple formulas.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var product = new Product({ netPrice: 100, vatRate: 20 });
var grossPrice = product.get('grossPrice');
    &lt;/pre&gt;    &lt;p&gt;        In this case, gross price would be 120.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;product.set({grossPrice: 300});
var netPrice = product.get('netPrice');
&lt;/pre&gt;    &lt;p&gt;        After gross price is update, netPrice will be recalculated and netPrice will be 250.&lt;br /&gt;
    &lt;/p&gt;    &lt;h3&gt;Concatenating fields&lt;/h3&gt;    &lt;p&gt;        Let's have a model to represent the person with first name and last name.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var Person = Backbone.Model.extend({
    initialize: function () {
        this.computedFields = new Backbone.ComputedFields(this);
    },

    computed: {
        fullName: {
            depends: ['firstName', 'lastName'],
            get: function (fields) {
                return fields.firstName + ' ' + fields.lastName;
            }
        }
    }
});
&lt;/pre&gt;    &lt;p&gt;        I'm skipping the setter cause we don't need to set full name here.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var person = new Person({firstName: 'Alexander', lastName: 'Beletsky'});
var fullName = person.get('fullName');
&lt;/pre&gt;    &lt;p&gt;        Full name 'Alexander Beletsky' is returned here.&lt;br /&gt;
    &lt;/p&gt;    &lt;h3&gt;Referenced objects&lt;/h3&gt;    &lt;p&gt;        Sometimes we have a models that only contains a reference to another model. All the time, we need to get referenced object we have to create some piece of code, which it typically copy-n-pasted thought the code base. Computed field could be a good idea to encapsulate that.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var Invoice = Backbone.Model.extend({
    initialize: function (attrs, options) {
        this.customers = options.customers;
        this.computedFields = new Backbone.ComputedFields(this);
    },

    computed: {
        customer: {
            depends: ['customerId'],
            get: function (fields) {
                return fields.customerId &amp;&amp; this.customers.get(fields.customerId);
            },
            set: function(customer, fields) {
                fields.customerId = customer.get('id');
            }
        }
    }
});
&lt;/pre&gt;    &lt;p&gt;        Here we have customer field, which is computed. &lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var invoice = new Invoice({}, { customers: collectionOfCustomers });
var customer = invoice.get('customer');
&lt;/pre&gt;    &lt;p&gt;        So, I'm able to get customer model even if invoice is just holding the invoice Id. &lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;invoice.set({customer: anotherCustomer});
var customerId = invoice.get('customerId');
    &lt;/pre&gt;    &lt;p&gt;        If I'm changing the customer of invoice, the 'customerId' would be initialized with id of 'anotherCustomer'.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        &lt;a href="https://github.com/alexanderbeletsky/backbone.computedfields"&gt;Backbone.ComputedFields&lt;/a&gt; is still pre-mature, but I already successfully used that in one of projects. The github page contains pretty much documentation, so you should have to problems of adopting it for personal needs.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=Ej0_wSOEfeA:7DaKdGtYgXo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=Ej0_wSOEfeA:7DaKdGtYgXo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=Ej0_wSOEfeA:7DaKdGtYgXo:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=Ej0_wSOEfeA:7DaKdGtYgXo:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/Ej0_wSOEfeA" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/4999385368740423358?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/4999385368740423358?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/Ej0_wSOEfeA/introducing-backbonecomputedfields.html" title="Introducing Backbone.ComputedFields" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/12/introducing-backbonecomputedfields.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYDQngzeCp7ImA9WhNWGUk.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8698629685661563480</id><published>2012-12-19T21:52:00.001+02:00</published><updated>2012-12-19T21:59:33.680+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-19T21:59:33.680+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="BabyStepsBackbone" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Baby steps to Backbone.js: Unit testing of views</title><content type="html">    &lt;p&gt;Previous time, we've implemented a Backbone model and wrote some meaningful tests for it.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Next very important Backbone's entry to test is View.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Views are central concept in framework. Views are actually ones who do stuff. We don't have Controller in Backbone, but according to Controller &lt;a href="http://www.itu.dk/courses/VOP/E2005/VOP2005E/8_mvc_krasner_and_pope.pdf"&gt;initial idea&lt;/a&gt; as user input handler, Backbone views following exactly the same architectural goal, so they could be treaded as controllers in some way. &lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;What to test?&lt;/h2&gt;&lt;p&gt;You should focus on such things: &lt;br /&gt;
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Initialization&lt;/strong&gt; - test that view is provided with all required inputs like: model or collection, localization texts, different options. If view is not able, say, render without some option, you should test that exception is thrown.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rendering &lt;/strong&gt; - test that required html appeared in view. I do not create those very strict, since they would be to fragile in case of markup changes, but still I check for major DOM elements are present and have right styles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Events&lt;/strong&gt; - test that view is correctly handle DOM events.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model changes and persistence&lt;/strong&gt; - test that changes in view are correctly propagated in model. If view is about to persist the model, that could tested as well.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;I see tests of views as kind of integration test. You communicate to DOM, listening to events, updating models or changing DOM elements state. It's typically that view tests are catching most regression issues.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;How to test?&lt;/h2&gt;&lt;p&gt;Fortunately, the Backbone views are designed in very testable way. You don't need any special HTML on test page, since view holding all it's DOM structure inside &lt;code&gt;this.el&lt;/code&gt;. By means of jQuery, it's easy to change DOM values or trigger events.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Since view also holds reference to model, it's easy to check model's attributes changes or spying on particular models methods.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;First red test,&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('FeedbackFormView.js spec', function () {
    var view, model;

    beforeEach(function () {
        view = new FeedbackFormView();
    });

    describe('when view is constructing', function () {

        it ('should exist', function () {
            expect(view).toBeDefined();
        });

    });
    &lt;/pre&gt;&lt;p&gt;Here we basically testing, that FeedbackFormView should exist, so as soon as function is in place, test should be green.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;FeedbackFormView could not exist without a model as well as default feedback text, that should be used as initial value of textbox. In the language of TDD, that means:&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('when view is initialized', function () {

    describe('without model', function () {

        it('should throw exception', function () {
            expect(function () {
                new FeedbackFormView();
            }).toThrow(new Error('model is required'));
        });

    });

    describe('without default feedback', function () {
            
        it('should throw exception', function () {
            expect(function () {
                new FeedbackFormView({model: new Backbone.Model() });
            }).toThrow(new Error('feedback is required'));
        });
    });

});
    &lt;/pre&gt;&lt;p&gt;To turn from Red to Green, let's add &lt;code&gt;initialize&lt;/code&gt; function to view,&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;initialize: function (options) {

    if (!this.model) {
        throw new Error('model is required');
    }

    if (!(options &amp;&amp; options.feedback)) {
        throw new Error('feedback is required');
    }

    this.feedback = options.feedback;
},
    &lt;/pre&gt;&lt;p&gt;Btw, after that change it's required to fix previous test, since it start to fail.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('FeedbackFormView.js spec', function () {
    var view, model;

    beforeEach(function () {
        view = new FeedbackFormView({model: new Feedback(), feedback: 'TDD is awesome..' });
    });

    describe('when view is constructing', function () {

        it ('should exist', function () {
            expect(view).toBeDefined();
        });

    });
    &lt;/pre&gt;&lt;p&gt;Now, let's test how rendering works.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('when view is rendered', function () {

    beforeEach(function () {
        view.render();
    });

    it ('should email field be empty', function () {
        expect(view.$el.find('input#email')).toHaveValue('');
    });

    it ('should website field be empty', function () {
        expect(view.$el.find('input#website')).toHaveValue('');
    });

    it ('should feedback field with default feedback', function () {
        expect(view.$el.find('textarea#feedback')).toHaveValue('TDD is awesome..');
    });

});
&lt;/pre&gt;&lt;p&gt;Here and after I'm using very nice Jasmine plugin, called &lt;a href="https://github.com/velesin/jasmine-jquery"&gt;jasmine-jquery&lt;/a&gt;. It adds a number of matchers, very useful for testing jQuery objects.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;We've tested initialization and rendering, now let's test last aspect, model changes and persistence.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Suppose a user inputs nothing, erases default feedback and presses submit button. Expected behavior is expressed with this test:&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('when form is submitted', function () {

    describe('no inputs are filled', function () {

        beforeEach(function () {
            view.$el.find('#email').val('').trigger('change');
            view.$el.find('#feedback').val('').trigger('change');
        });

        beforeEach(function () {
            view.$el.find('#submit').trigger('click');
        });

        it('email field should be invalidated', function () {
            expect(view.$el.find('.control-group.email')).toHaveClass('error');
        });

        it('feedback field should be invalidated', function () {
            expect(view.$el.find('.control-group.feedback')).toHaveClass('error');
        });

        it('website field should be valid', function () {
            expect(view.$el.find('.control-group.website')).not.toHaveClass('error');
        });

    });
&lt;/pre&gt;&lt;p&gt;That's cool. After those tests are passing, we can test that if only email is filled, but feedback is still empty, we are not able to submit the form. By analogy of previous test,&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('only email field filled', function () {

    beforeEach(function () {
        view.$el.find('#email').val('a@a.com').trigger('change');
        view.$el.find('#feedback').val('').trigger('change');
    });

    beforeEach(function () {
        view.$el.find('#submit').trigger('click');
    });

    it('email field should be valid', function () {
        expect(view.$el.find('.control-group.email')).not.toHaveClass('error');
    });

    it('feedback field should be invalidated', function () {
        expect(view.$el.find('.control-group.feedback')).toHaveClass('error');
    });

    it('website field should be valid', function () {
        expect(view.$el.find('.control-group.website')).not.toHaveClass('error');
    });

});
&lt;/pre&gt;&lt;p&gt;And finally, if view is filled correctly,&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;describe('email and feedback filled', function () {

    beforeEach(function () {
        spyOn(view.model, 'save').andCallThrough();
    });

    beforeEach(function () {
        view.$el.find('#email').val('a@a.com').trigger('change');
        view.$el.find('#feedback').val('some feedback').trigger('change');
    });

    beforeEach(function () {
        view.$el.find('#submit').trigger('click');
    });

    it('should show no errors', function () {
        expect(view.$el.find('.error').length).toBe(0);
    });

    it('should save model', function () {
        expect(view.model.save).toHaveBeenCalled();
    });

});
&lt;/pre&gt;&lt;p&gt;Here, we test 2 things: first, that no validation errors appeared on form and second that &lt;code&gt;save&lt;/code&gt; method of model is called. Jasmine built-in spy framework is used here. You can setup on any function of any object and then verify that function has (or has not) been called.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I'm skipping the implementation of that view, but you can find the code of application in &lt;a href="https://gist.github.com/4330928"&gt;gist&lt;/a&gt;.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Conclusions&lt;/h2&gt;&lt;p&gt;While you typically start with defining and testing models in your application, view is integration test that helps to test actual behavior of application, depending on model states and events. You should define how "deep" you want to test the view, but my proposal is to focus on initialization, rendering, changes (validation) and persistence.&lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=GVX6UBQXilc:Br9Ar07yTb0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=GVX6UBQXilc:Br9Ar07yTb0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=GVX6UBQXilc:Br9Ar07yTb0:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=GVX6UBQXilc:Br9Ar07yTb0:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/GVX6UBQXilc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8698629685661563480?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8698629685661563480?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/GVX6UBQXilc/baby-steps-to-backbonejs-unit-testing.html" title="Baby steps to Backbone.js: Unit testing of views" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/12/baby-steps-to-backbonejs-unit-testing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cMQHk4eip7ImA9WhNXE0o.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-7594141954359019078</id><published>2012-12-01T16:11:00.000+02:00</published><updated>2012-12-01T16:11:21.732+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-12-01T16:11:21.732+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Trackyt.net" /><title>Retrospective of Trackyt.net or Best Project I Ever Accomplished</title><content type="html">    &lt;p&gt;        It's been to years ago, I've &lt;a href="http://www.beletsky.net/2010/11/ive-release-my-own-product-trackytnet.html"&gt;released&lt;/a&gt; my own project - Trackyt.net. Month ago I've cancelled my VPS lease contract, so your would not see it available at &lt;a href="http://trackyt.net"&gt;http://trackyt.net&lt;/a&gt; anymore.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        This project is first attempt to release something. I had some pet projects before, but never ever made them done. Trackyt.net started as simple application to learn some JavaScript programming and HTML. It turns out to be much, much, much more. Even it seems to be very simple, but I've spent a lot of energy on it.&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh6.googleusercontent.com/-C1oDnTeZXIY/ULoMUOx3XPI/AAAAAAAAMuc/3GuIq-ra1UI/s1366/image-1.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh6.googleusercontent.com/-C1oDnTeZXIY/ULoMUOx3XPI/AAAAAAAAMuc/3GuIq-ra1UI/s1366/image-1.png" style="width: 620px"/&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        The product did not gather any meaningful amount of users neither good amount of traffic. For almost 2 years I was investing money/time on it. So, from the first sight it might appear as failed project.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Any kind of business should be evaluated in terms of assets. It's not necessarily means money. Or more correctly, it does not meant "direct" money. I had no paying customers and I actually never thought to sell the product. But, I can prove it - every hour I spent on the project got back to me as value. And the most valuable asset for developer is skill, of cause.&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh6.googleusercontent.com/-OLeITq9xGf4/ULoMUBovQkI/AAAAAAAAMuU/lk7SvXWvvFc/s1086/image-2.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh6.googleusercontent.com/-OLeITq9xGf4/ULoMUBovQkI/AAAAAAAAMuU/lk7SvXWvvFc/s1086/image-2.png" style="width: 620px"/&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        I'll try to analyze what actually happened:&lt;br /&gt;
    &lt;/p&gt;    &lt;ul&gt;        &lt;li&gt;&lt;strong&gt;Web development and design:&lt;/strong&gt; even my professional involvement into web applications, did not give me a feeling of web development. I &lt;a href="http://www.beletsky.net/2011/03/aspnet-developers-disease.html"&gt;blame&lt;/a&gt; ASP.NET Web Forms for that, but I realized that I lack that kind of skill. That was my first project were I did everything by myself, all HTML/CSS/JS were handmade, not stupid WebControls. My eyes opened on how many things I did not understand, how difficult the front-end might be. Crafting of UI is a huge pleasure for me, I simply like beautiful things. 2 years after I will never call Trackyt.net beautiful, but it was a great point to start.&lt;br /&gt;
            &lt;p&gt;                &lt;i&gt;Outcome&lt;/i&gt;: I overstepped the uncertainty and fears of front-end. During the JavaScript programming. I've seen a lot of value in front-end MVC frameworks, so I had no doubts of moving from jQuery based apps to Backbone.js (or other MV*) frameworks. I did a &lt;a href="https://speakerdeck.com/alexanderbeletsky"&gt;several speeches&lt;/a&gt; of JavaScript applications development and got really cool feedback on it.&lt;br /&gt;
            &lt;/p&gt;        &lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Test driven development:&lt;/strong&gt; practicing TDD for quite long years already, so Trackyt.net was not my first project were I applied the technique. The difference was that usually the we work with some legacy code at work, so TDD could be difficult to apply. Starting that project I had strong opinion on TDD and literally TDD'ed everything. UI, Controllers, Repositories.. JavaScript and C#. That was so great experience, I never felt on any other projects. During Trackyt.net I think I moved from &lt;a href="http://martinfowler.com/bliki/ShuHaRi.html"&gt;Shu&lt;/a&gt; to &lt;a href="&lt;/a&gt;"&gt;Ha&lt;/a&gt; level of testing. Now, I &lt;a href="http://www.beletsky.net/2011/11/develop-with-tests.html"&gt;more clearly&lt;/a&gt; see what and when should I test to stay in good shape of application.&lt;br /&gt;
        &lt;/li&gt;
        &lt;p&gt;            &lt;i&gt;Outcome&lt;/i&gt;: currently I'm professional TDD trainer at &lt;a href="http://xpinjection.com/"&gt;XP Injection&lt;/a&gt; and Trackyt.net much influenced that it happened. I share my experience with guys I show some examples of code there. I &lt;a href="http://www.beletsky.net/search/label/TDD"&gt;wrote&lt;/a&gt; a bunch of blog posts on TDD and it's Trackyt.net who gave most inputs and insights. I've &lt;a href="http://www.beletsky.net/2010/12/testing-rest-services-with-javascript.html"&gt;implemented&lt;/a&gt; integration tests for my API based FuncUnit and that blog post became the part of &lt;a href="http://javascriptweekly.com/"&gt;JavaScript Weekly&lt;/a&gt; and still remains one of the best reads in my blog. I've learned UI testing and &lt;a href="http://www.beletsky.net/2011/04/functional-tests-must-not-be-done-first.html"&gt;formed&lt;/a&gt; my opinion on that.
        &lt;/p&gt;        &lt;li&gt;&lt;strong&gt;ASP.NET MVC:&lt;/strong&gt; Never used ASP.NET MVC before, I armed with &lt;a href="http://books.google.com.ua/books/about/Pro_ASP_NET_MVC_2_Framework.html?hl=uk&amp;id=lFSPoYt9deAC"&gt;great book&lt;/a&gt; by Steven Sanderson I've started to learn new framework. And Trackyt.net was main playground. Starting up with MVC2 and lately ported it to MVC3 I had a chance to play different aspects of framework. ASP.NET MVC was my first serious step into web development world.&lt;br /&gt;
        &lt;/li&gt;
        &lt;p&gt;            &lt;i&gt;Outcome:&lt;/i&gt; I became a huge fan of this technology, learning it from deep and &lt;a href="http://www.beletsky.net/search/label/InsideMVC"&gt;posting&lt;/a&gt; information on it. I had a few speeches about ASP.NET MVC.. and the biggest one on MS SWIT 2012, there ~300 persons were listened to me. Then the company I worked to were deciding about back-end technology for API of new product I helped to integrate ASP.NET MVC into existing web site and we successfully built API on it. I assisted my team mates to understand the framework, it was not difficult at all, since I knew the stuff. Currently I have a &lt;a href="http://xpinjection.com/trainings/mvc-net-development/"&gt;training course&lt;/a&gt; on ASP.NET MVC as well and already conducted some.
        &lt;/p&gt;        &lt;li&gt;&lt;strong&gt;API oriented architecture:&lt;/strong&gt; popularized by Twitter and GMail, the architecture and having RESTfull JSON based service behind and the JavaScript-driven application on front-end, was my high-level architecture for Trackyt.net. &lt;br /&gt;
            &lt;p&gt;                &lt;i&gt;Outcome:&lt;/i&gt; I successfully used the same ideas on other projects and it worked really well. For now I'm consulting few companies that tries to adopt same ideas. The most popular &lt;a href="http://www.beletsky.net/2011/01/implementation-of-rest-service-with.html"&gt;post&lt;/a&gt; in my blog is about build REST(like) services with ASP.NET MVC. &lt;br /&gt;
            &lt;/p&gt;        &lt;/li&gt;
        &lt;li&gt;&lt;strong&gt;Continuous Delivery:&lt;/strong&gt; being annoyed by manual update of production environment I've &lt;a href="http://www.beletsky.net/2011/05/continuous-production-make-it-work.html"&gt;built&lt;/a&gt; simple continuous delivery pipeline that worked really great for me. During the way I've met such great tools as Jenkins, UppercuT, RoundhousE etc. That was my first try of this approach and I felt huge power and advantages of Continuous Delivery. Slightly it became one of the professional areas of interests for me.&lt;br /&gt;
        &lt;/li&gt;
        &lt;p&gt;            &lt;i&gt;Outcome:&lt;/i&gt; Continuous Delivery and &lt;a href="https://github.com/chucknorris"&gt;Chuck Norris&lt;/a&gt; tools was the topic of my first talk on &lt;a href="http://kievalt.net/"&gt;KievALT.NET&lt;/a&gt;. Since then I became an active participant of community and I really like it. Also, I'm talking about things like RoundhousE on my other speeches and trainings and I got a lot of pleasure than people stand by saying: "You know, we've tried that and it worked so nice, thanks a lot".
        &lt;/p&gt;        &lt;li&gt;&lt;strong&gt;Code base:&lt;/strong&gt; the code base of application is rather small. There is C#, JavaScript, SQL and some NAnt scripts. A lot of things I used there I still copy and paste (or at least taking a look) from Trackyt.net to my current projects. It became a kind of cook book, from there I could quickly pick up some recipe. &lt;br /&gt;
        &lt;/li&gt;
        &lt;p&gt;            &lt;i&gt;Outcome:&lt;/i&gt; I didn't thought above that initially, but Trackyt.net codebase also helping me to see what improvements I've made so far. For instance, I reviewed the API controllers recently and realized that I would never write anything like that. Having some code that you produced year or two ago you peer and compare gives some really interesting insights. Besides of application code itself, I've made an C# API adapter and the most significant outcome is &lt;a href="https://github.com/alexanderbeletsky/elmah.mvc"&gt;ELMAH.MVC&lt;/a&gt;.
        &lt;/p&gt;    &lt;/ul&gt;    &lt;p&gt;        Concluding this, I would say - Trackyt.net changed the things radically. I've became a speaker on &lt;a href="http://kievalt.net/"&gt;KievALT.NET&lt;/a&gt; and &lt;a href="http://xpinjection.com/uadevclub/"&gt;UADevClub&lt;/a&gt; communities, my blog received an &lt;a href="http://java.dzone.com/users/alexanderb"&gt;MVB&lt;/a&gt; status, I improved my skills and knowledge and I do trainings and consulting. Basically, I've "rebooted" developer inside me and saw my way of constant learning and improving.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Looking back I definitely say - it was only possible because of Trackyt.net.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Without any doubts, that was the most successful project to me!&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=ua692uYZ-p8:QAVGJbFg7_c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=ua692uYZ-p8:QAVGJbFg7_c:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=ua692uYZ-p8:QAVGJbFg7_c:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=ua692uYZ-p8:QAVGJbFg7_c:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/ua692uYZ-p8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7594141954359019078?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7594141954359019078?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/ua692uYZ-p8/retrospective-of-trackytnet-or-best.html" title="Retrospective of Trackyt.net or Best Project I Ever Accomplished" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh6.googleusercontent.com/-C1oDnTeZXIY/ULoMUOx3XPI/AAAAAAAAMuc/3GuIq-ra1UI/s72-c/image-1.png" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2012/12/retrospective-of-trackytnet-or-best.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8MQnk5fip7ImA9WhNXEE0.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-4385931917176266006</id><published>2012-11-27T10:16:00.000+02:00</published><updated>2012-11-27T11:01:23.726+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-27T11:01:23.726+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="KievAltNet" /><title>Kiev ALT.NET Re-launch with Jimmy Bogard</title><content type="html">    &lt;p&gt;Good news, &lt;a href="http://kievalt.net/"&gt;Kiev ALT.NET&lt;/a&gt; community! One of the best know ALT.NET developers &lt;a href="http://twitter.com/jbogard"&gt;Jimmy Bogard&lt;/a&gt; is visiting us on December 11. It's been awhile since the last meetup we had, so it's just great time to gather again and listen to the presentation Jimmy prepared for us.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;There will be a talk with intriguing name &lt;i&gt;"Real World Polyglot Persistence"&lt;/i&gt;. Here is the short description of it.&lt;br /&gt;
&lt;/p&gt;&lt;blockquote&gt;It always sounds easy - "use the best tool for the job". With very isolated systems, it's easy to decide RDBMS for one application, Redis for another and Cassandra for somethings else. When it comes time to building systems with multiple persistent stores, we're met with challenges in integration, existing applications, and push back from IT administrators. In this session, we'll look at the multitude of challenges of achieving polyglot persistence nirvana, and strategies for addressing associated risks.&lt;br /&gt;
&lt;/blockquote&gt;&lt;p&gt;I don't know about you, but for me it sound extremely interesting.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Meetup will take place in &lt;a href="http://ciklum.net/"&gt;Ciklum&lt;/a&gt;, the most spectacular place in Kiev - &lt;a href="http://www.ciklum.com/upload/iblock/41b/Ciklum_SkyPoint_Kyiv_20Floor.jpg"&gt;Sky Point&lt;/a&gt; at 19-00. As always, &lt;a href="http://ciklum.net/"&gt;Ciklum&lt;/a&gt; happily agreed host us. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Participation is completely free, but you have to register before. Registration is available &lt;a href="https://docs.google.com/spreadsheet/viewform?formkey=dDlsSS1QenUyMVVkRWM3RmJKZzB1Wnc6MQ"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;The information support by our good friend at &lt;a href="http://wp7rocks.com/"&gt;wp7rocks.com&lt;/a&gt;.&lt;br /&gt;
&lt;/p&gt;&lt;img src="https://si0.twimg.com/profile_images/1246801773/Headshot3.png" /&gt;&lt;br /&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=C0jQ3mH-1-8:2SfaNXwMPc0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=C0jQ3mH-1-8:2SfaNXwMPc0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=C0jQ3mH-1-8:2SfaNXwMPc0:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=C0jQ3mH-1-8:2SfaNXwMPc0:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/C0jQ3mH-1-8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/4385931917176266006?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/4385931917176266006?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/C0jQ3mH-1-8/kiev-altnet-re-launch-with-jimmy-bogard.html" title="Kiev ALT.NET Re-launch with Jimmy Bogard" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/11/kiev-altnet-re-launch-with-jimmy-bogard.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkACSHozfCp7ImA9WhNQFkQ.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-3393125611043578824</id><published>2012-11-23T19:12:00.001+02:00</published><updated>2012-11-23T19:12:49.484+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-23T19:12:49.484+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mind" /><title>Pair Programming Takes Double Effort</title><content type="html">    &lt;p&gt;        Pair programming is very known as efficient technique of writing code. Originally appeared as one of key XP practices, it got a lot of traction. You can find many publication about Pair Programming and seems everybody clearly understands it's value. Being a XP trainer and visiting conferences related to engineering practices I usually see such situation: the question goes to the crowd "How many of you do practice Pair Programming?" and I can give a bet, only few hands will appear.. very few people are actually practicing Pair Programming. Why?&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Because Pair Programming is damn hard!&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        There could be 2 situations with PP: first one, then both guys are completely different levels of skills - it turns to be that one (more experienced) is writing and thinking all the time, another one is almost watcher helping to find a grammar errors in code comments. At the end of the day you got 2 mans powers producing 1 mans power work. Easy journey.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Second one is different, is then 2 guys are same or equally same level. Working in such pair could be compared to wresting. You literally have to fight to move on. All the time you under pressure of another man's opinion, usually strong one. You struggle much to get consensus on different topics. You are talking all the time and arguing all the time. Sure, you got shinny-working-super-cool results much more faster by working such pair. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        But there is a problem - after 3-4 hours of working that way you will be completely exhausted. Believe me, you are absolutely useless after 4 hours session of true Pair Programming. Thinking, focusing, arguing, writing, testing, debugging over and over again. It takes a lot of energy. Working a 40 hours week in strong pair will let you feel like 80 hours week. There is also psychological side as well: 2 persons could not match each over, so working in pair would be like hell. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Pair programming takes double effort. You should not plan PP session for a whole day, half day as maximum. In my opinion it's not valuable to do every task in pair, simply it's not productive. Pick up most difficult ones, ones that requires cross-functional expertise or most risky ones. As problem well kick-started, rest of things might go in parallel. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I really like Pair Programming, but I would not use it as day-to-day practice as XP suggests. Most of the time, it's more efficient to work alone.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=aU0i6DUqn_s:oMzQAApakKQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=aU0i6DUqn_s:oMzQAApakKQ:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=aU0i6DUqn_s:oMzQAApakKQ:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=aU0i6DUqn_s:oMzQAApakKQ:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/aU0i6DUqn_s" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/3393125611043578824?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/3393125611043578824?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/aU0i6DUqn_s/pair-programming-takes-double-effort.html" title="Pair Programming Takes Double Effort" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/11/pair-programming-takes-double-effort.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcARXg8eip7ImA9WhNQFUo.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-7424300355359506953</id><published>2012-11-22T11:54:00.000+02:00</published><updated>2012-11-22T11:54:04.672+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-22T11:54:04.672+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="BabyStepsBackbone" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Baby steps to Backbone.js: Unit testing of models</title><content type="html">&lt;p&gt;            Unit testing is important part of development process. If you care about the application state and code quality, sooner or later you start to automate the tests. My experience shows, sooner is better option. There are several approaches to unit testing, `test-first` and `test-after`. There are many holy wars appears on that topic. I would say, both options works - but `test-first` or test driven development, works better for me. &lt;br /&gt;
        &lt;/p&gt;        &lt;p&gt;            By the end of the day, it's only important that tests exists and helping to catch regression bugs. Still, developing by `test-first` helps to see the problem before ahead and in general provides better code quality (that would conclude the holy war). &lt;br /&gt;
        &lt;/p&gt;        &lt;p&gt;            Today we going to write some tests, that would cover our existing model class &lt;code&gt;Feedback.js&lt;/code&gt;. Since the code is already written, we will go `test-after` approach. Fortunately, the code is quite simple, so it would not make a problem to unit test that. But before, let's setup our testing infrastructure.&lt;br /&gt;
        &lt;/p&gt;        &lt;h2&gt;Folders and files&lt;/h2&gt;        &lt;p&gt;            We'll have a new folder called `spec`. Inside the spec folder, I'll have `models` and `views` folders that would contain tests for models and views.&lt;br /&gt;
        &lt;/p&gt;        &lt;a href="https://lh3.googleusercontent.com/-Ey7odJOnLXM/UK3wux_CNDI/AAAAAAAAMIY/B0lXl2K_cDM/s620/image-1.png"&gt;&lt;br /&gt;
            &lt;img src="https://lh3.googleusercontent.com/-Ey7odJOnLXM/UK3wux_CNDI/AAAAAAAAMIY/B0lXl2K_cDM/s620/image-1.png"/&gt;&lt;br /&gt;
        &lt;/a&gt;&lt;br /&gt;
        &lt;h2&gt;Tests runner&lt;/h2&gt;        &lt;p&gt;            I'll be using &lt;a href="http://pivotal.github.com/jasmine/"&gt;Jasmine&lt;/a&gt; test framework. It's very easy to setup it, what we need is &lt;code&gt;jasmine.js&lt;/code&gt; and &lt;code&gt;jasmine.css&lt;/code&gt; to be placed on proper folders and setup a test page. Test page is a simple html file, which will be entry point for our testing. If you download jasmine &lt;a href="https://github.com/pivotal/jasmine/downloads"&gt;standalone bundle&lt;/a&gt; you will see &lt;code&gt;SpecRunner.html&lt;/code&gt; inside. It could be easily tailored for custom needs.&lt;br /&gt;
        &lt;/p&gt;        &lt;p&gt;            In the head part of &lt;code&gt;tests.html&lt;/code&gt; we need to reference all required .css and .js files.&lt;br /&gt;
        &lt;/p&gt;        &lt;pre class="brush: html"&gt;&amp;lt;title&amp;gt;Feedback form specs&amp;lt;/title&amp;gt;

&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;content/jasmine.css&amp;quot;&amp;gt;

&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/libs/jquery-1.7.2.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/libs/underscore.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/libs/backbone.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/libs/jasmine.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/libs/jasmine-html.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/libs/mock-ajax.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;!-- Sources --&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/src/models/Feedback.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;!-- Specs --&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;/scripts/spec/models/Feedback.spec.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &lt;/pre&gt;        &lt;h2&gt;Jasmine tests in essence&lt;/h2&gt;        &lt;p&gt;            Testing with Jasmine is fun and easy. Jasmine is BDD-style framework, so if you practiced TDD with another frameworks, the style might confuse initially. Let's review the Jasmine test skeleton.&lt;br /&gt;
        &lt;/p&gt;        &lt;pre class="brush: js"&gt;describe('Jasmine spec', function () {
    var value;

    beforeEach(function () {
        value = 1;
    });

    it ('should fail', function () {
        expect(value).toBe(0);
    });

    describe('when value is changed', function () {
        beforeEach(function () {
            value = 0;
        });

        it ('should pass', function () {
            expect(value).toBe(0);
        })
    });
});
&lt;/pre&gt;        &lt;p&gt;            In this example, &lt;code&gt;value&lt;/code&gt; is our SUT (System under test). &lt;code&gt;beforeEach()&lt;/code&gt; function is `context-establish` function, where SUT is initialized (in TDD it's both arrange/act). &lt;code&gt;it&lt;/code&gt; function is assert part. Here, we set our expectations about which state should SUT be in to. Notice, that &lt;code&gt;beforeEach&lt;/code&gt; are nested into &lt;code&gt;describe&lt;/code&gt;, so you tweek SUT depending on case.&lt;br /&gt;
        &lt;/p&gt;        &lt;h2&gt;Writing some tests&lt;/h2&gt;        &lt;p&gt;            The only one functionality that &lt;code&gt;Feedback.js&lt;/code&gt; model contains currently is validation. Let's test that.&lt;br /&gt;
        &lt;/p&gt;        &lt;pre class="brush: js"&gt;describe('Feedback.js spec', function () {
    var model;

    beforeEach(function () {
        model = new Feedback();
    });

    describe('when model is validating', function () {
        var errors;
    });
});
&lt;/pre&gt;        &lt;p&gt;            This is something to start with. It does not do any asserts, so now we'll add some real cases. First case, is than both `email` and `feedback` attributes are absent.&lt;br /&gt;
        &lt;/p&gt;        &lt;pre class="brush: js"&gt;describe('when email and feedback fields are absent', function () {
    beforeEach(function () {
        errors = model.validate({});
    });

    it ('should have 2 errors', function () {
        expect(errors.length).toBe(2);
    });

    it ('should have email fields as invalid', function () {
        expect(errors[0].name).toBe('email');
    });

    it ('should have feedback field as invalid', function () {
        expect(errors[1].name).toBe('feedback');
    });
});
&lt;/pre&gt;        &lt;p&gt;            It's is possible that user put email, but forgot about feedback.&lt;br /&gt;
        &lt;/p&gt;        &lt;pre class="brush: js"&gt;describe('when email is set, but feedback is absent', function () {
    beforeEach(function () {
        errors = model.validate({ email: 'a@a.com'});
    });

    it ('should have 1 error', function () {
        expect(errors.length).toBe(1);
    });

    it ('should have feedback field as invalid', function () {
        expect(errors[0].name).toBe('feedback');
    });

    it ('should have error message', function () {
        expect(errors[0].message).toBeDefined();
    });
});
&lt;/pre&gt;        &lt;p&gt;            Moving on, user might put feedback but forgot about email.&lt;br /&gt;
        &lt;/p&gt;        &lt;pre class="brush: js"&gt;describe('when feedback is set, but email is absent', function () {
    beforeEach(function () {
        errors = model.validate({ feedback: 'TDD is awesome'});
    });

    it ('should have 1 error', function () {
        expect(errors.length).toBe(1);
    });

    it ('should have email field as invalid', function () {
        expect(errors[0].name).toBe('email');
    });

    it ('should have error message', function () {
        expect(errors[0].message).toBeDefined();
    });
});
&lt;/pre&gt;        &lt;h2&gt;Tests report&lt;/h2&gt;        &lt;p&gt;            If you now try to run &lt;code&gt;test.html&lt;/code&gt; in browser, you will something like that.&lt;br /&gt;
        &lt;/p&gt;        &lt;a href="https://lh4.googleusercontent.com/-K9NtZKm7pso/UK3wvG3mDxI/AAAAAAAAMIc/kQL0Ai1XX_A/s620/image-2.png"&gt;&lt;br /&gt;
            &lt;img src="https://lh4.googleusercontent.com/-K9NtZKm7pso/UK3wvG3mDxI/AAAAAAAAMIc/kQL0Ai1XX_A/s620/image-2.png"/&gt;&lt;br /&gt;
        &lt;/a&gt;&lt;br /&gt;
        &lt;h2&gt;Conclusions&lt;/h2&gt;        &lt;p&gt;            Testing of Backbone.Model's is pretty simple thing. It's nothing more than testing some business logic, that might reside inside. Testing of views is a bit trickier thing, but we will see how to do that next time.&lt;br /&gt;
        &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=yp41CDsssJk:b6Oz7heGPN0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=yp41CDsssJk:b6Oz7heGPN0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=yp41CDsssJk:b6Oz7heGPN0:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=yp41CDsssJk:b6Oz7heGPN0:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/yp41CDsssJk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7424300355359506953?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7424300355359506953?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/yp41CDsssJk/baby-steps-to-backbonejs-unit-testing.html" title="Baby steps to Backbone.js: Unit testing of models" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/-Ey7odJOnLXM/UK3wux_CNDI/AAAAAAAAMIY/B0lXl2K_cDM/s72-c/image-1.png" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2012/11/baby-steps-to-backbonejs-unit-testing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUGQ3s4eip7ImA9WhNRF08.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-7958742100646826066</id><published>2012-11-12T15:50:00.000+02:00</published><updated>2012-11-12T15:50:22.532+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-12T15:50:22.532+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><title>JavaScript Object Creation by New Operator</title><content type="html">&lt;p&gt;        There are different approaches of how to create object in JavaScript. C# and Java programmers are commonly starting with creation by new operator, since it very close to same practice they got used to.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;function Person (name) {
    this.name = name;
}

var person = new Person('John Smith');
console.log(person.name);
    &lt;/pre&gt;    &lt;p&gt;        If you try to run this code, you will see 'John Smith' in console. Now, try to delete new operator.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Instead of 'John Smith' you will see undefined. Why?&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The difference is that without new operator it is just function call. During the call `this` points global namespace. If you running the code in browser, global namespace is bind to `window`.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It's important to understand how new operator works. Internally, operator new is converted to NEW(Person, 'John Smith');. It does several things.&lt;br /&gt;
    &lt;/p&gt;    &lt;ol&gt;        &lt;li&gt;Creates new native object and initializes the __proto__ of object by function.prototype.&lt;/li&gt;
        &lt;li&gt;Calls function, applying newly created object as value for &lt;code&gt;this&lt;/code&gt;.&lt;/li&gt;
        &lt;li&gt;Returns newly created object.&lt;/li&gt;
    &lt;/ol&gt;    &lt;p&gt;        It can be expressed in this kind of pseudo-code:&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;function NEW(f) {
    var obj = { '__proto__': f.prototype };
    f.apply(obj, arguments.slice(1));
    return obj;
}
&lt;/pre&gt;    &lt;p&gt;        (It's a bit more complex actually, for details check this &lt;a href="http://stackoverflow.com/questions/6750880/javascript-how-does-new-work-internally"&gt;great answer&lt;/a&gt; on SO).&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It means that during function call with `new operator()`, &lt;code&gt;this&lt;/code&gt; always points to a new object, created based on function prototype. You can initialize the properties of new object inside the function. It's no longer a simple function, but it is constructing function, or more simply - constructor.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        To distinguish between constructors (that are always supposed to be called with `new`) and simple function, there is a convention to name a constructors with capital first letter (not person(), but Person()), just to give you some tips while you writing the code.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Knowing NEW() details of work and following simple conventions for constructors will help you to understand language better and prevent many stupid errors.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=_jvYtEhZ2ko:5BRD9gE9iAM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=_jvYtEhZ2ko:5BRD9gE9iAM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=_jvYtEhZ2ko:5BRD9gE9iAM:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=_jvYtEhZ2ko:5BRD9gE9iAM:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/_jvYtEhZ2ko" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7958742100646826066?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7958742100646826066?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/_jvYtEhZ2ko/javascript-object-creation-by-new.html" title="JavaScript Object Creation by New Operator" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/11/javascript-object-creation-by-new.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkIGQXw-cCp7ImA9WhNRFEo.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-1803898004723047836</id><published>2012-11-09T17:21:00.001+02:00</published><updated>2012-11-09T17:22:00.258+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-09T17:22:00.258+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ELMAH.MVC" /><title>ELMAH.MVC 2.0.2 is out</title><content type="html">    &lt;p&gt;&lt;a href="http://nuget.org/packages/Elmah.MVC"&gt;ELMAH MVC 2.0.2&lt;/a&gt; has been just pushed recently. This is a contribution by &lt;a href="https://github.com/jamescrowley"&gt;James Crowley&lt;/a&gt; which adds a special configuration key that prevents ELMAH.MVC to setup a global `HandleErrorAttribute()`. It's in particular useful, than you already setup some configuration inside the app, so you don't want default behavior.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Inside the &lt;code&gt;web.config&lt;/code&gt; file you will find a configuration setting for that.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: plain"&gt;&amp;lt;appSettings&amp;gt;
 &amp;lt;add key=&amp;quot;elmah.mvc.disableHandler&amp;quot; value=&amp;quot;false&amp;quot; /&amp;gt;
 &amp;lt;add key=&amp;quot;elmah.mvc.disableHandleErrorFilter&amp;quot; value=&amp;quot;false&amp;quot; /&amp;gt;
 &amp;lt;add key=&amp;quot;elmah.mvc.requiresAuthentication&amp;quot; value=&amp;quot;false&amp;quot; /&amp;gt;
 &amp;lt;add key=&amp;quot;elmah.mvc.allowedRoles&amp;quot; value=&amp;quot;*&amp;quot; /&amp;gt;
 &amp;lt;add key=&amp;quot;elmah.mvc.route&amp;quot; value=&amp;quot;elmah&amp;quot; /&amp;gt;
&amp;lt;/appSettings&amp;gt;
    &lt;/pre&gt;&lt;p&gt;It is &lt;code&gt;elmah.mvc.disableHandleErrorFilter&lt;/code&gt;. By default it's `false`, meaning `HandleErrorAttribute()` from ELMAH.MVC is used. To disable it, just set &lt;code&gt;true&lt;/code&gt; to this setting.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;And btw, it's already 30.000 downloads of NuGet package! Huge number, thanks a lot for all users and contributors.&lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=xJpzGhRBlhY:3Tg1e4RBLlc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=xJpzGhRBlhY:3Tg1e4RBLlc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=xJpzGhRBlhY:3Tg1e4RBLlc:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=xJpzGhRBlhY:3Tg1e4RBLlc:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/xJpzGhRBlhY" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/1803898004723047836?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/1803898004723047836?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/xJpzGhRBlhY/elmahmvc-202-is-out.html" title="ELMAH.MVC 2.0.2 is out" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/11/elmahmvc-202-is-out.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIHQ3cyeip7ImA9WhNRE0s.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-193781415320351457</id><published>2012-11-08T09:42:00.000+02:00</published><updated>2012-11-08T09:42:12.992+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-08T09:42:12.992+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="BabyStepsBackbone" /><title>Baby steps to Backbone.js: Model Validation</title><content type="html">    &lt;p&gt;        Let's go back for a moment for &lt;a href="http://www.beletsky.net/2012/10/baby-steps-to-backbonejs-starting-up.html"&gt;previous&lt;/a&gt; post where we started to bootstrap some basic Backbone.js application. It's very simple now, just gathering all data and posting those data to server.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Any reliable system is almost impossible without validation. If some field is required or must conform to some particular rule, it should be validated as soon as possible and validation information should be displayed to user. User then applies corrections and re-submit data.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        In case of `Feedback` model, we are interested that user always input her email and feedback message. Backbone.js provides very straight forward for models validation. If model requires validation, it should implement &lt;a href="http://backbonejs.org/#Model-validate"&gt;validate&lt;/a&gt; method.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, let's extend our model with validate method.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var Feedback = Backbone.Model.extend({
    url: '/feedback',

    defaults: {
        'email': '',
        'website': '',
        'feedback': ''
    },

    validate: function (attrs) {
        if (!attrs.email) {
            return 'Please fill email field.';
        }
        if (!attrs.feedback) {
            return 'Please fill feedback field.';
        }
    }
});
    &lt;/pre&gt;    &lt;p&gt;        As you can see, in case of email or feedback is missing, we just simply return string with error message.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        To better understand what's going on, let's look on some piece of the code from Backbone.js framework. Namely, to `_validate` method of `Backbone.Model`, which is actually responsible for validation.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;_validate: function(attrs, options) {
    if (options.silent || !this.validate) return true;
    attrs = _.extend({}, this.attributes, attrs);
    var error = this.validate(attrs, options);
    if (!error) return true;
    if (options &amp;&amp; options.error) {
       options.error(this, error, options);
    } else {
        this.trigger('error', this, error, options);
    }
    return false;
}
&lt;/pre&gt;    &lt;p&gt;        You can see, if `validate` returns either undefined or null or false, `_validate` just returns true - meaning the model is valid. Otherwise, it would check if `options.error` function initialized and call it, if not model event `error` is triggered.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        During the model saving, we typically provide both success and error callbacks. It means, that error callback will be called, if model does not pass validation requirements. Inside the callback, we might decided what to do with errors. Right now, let's just do alert.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var options = {
    success: function () {
        alert('Thanks for the feedback!');
    },
    error: function (model, error) {
        alert(error);
    }
};

var feedback = {
    email: this.$('#email').val(),
    website:  this.$('#website').val(),
    feedback: this.$('#feedback').val()
};

this.model.save(feedback, options);
    &lt;/pre&gt;    &lt;p&gt;        Notice that `error` callback receiving model itself as first argument and error object (one returned from `validate` method) as second argument. Let's try this code: leave email and feedback fields empty and press submit button.&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh3.googleusercontent.com/-BtV9yCmh3T8/UJtgc5Nk4CI/AAAAAAAALnQ/d671woxZwrE/s621/image-1.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh3.googleusercontent.com/-BtV9yCmh3T8/UJtgc5Nk4CI/AAAAAAAALnQ/d671woxZwrE/s621/image-1.png"/&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        There are several drawback of such implementation, though. First of all, `alert` windows are awful, second if user corrects email, next time she presses the submit button next alert with another message appears. This is terrible UX, so let's fix it.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        So, we should basically do 2 things: aggregate all errors during validation and apply some nice styles to errors.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Instead of returning simple strings, we'll return an array of objects, containing name of failed and field and message.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;validate: function (attrs) {
    var errors = [];

    if (!attrs.email) {
        errors.push({name: 'email', message: 'Please fill email field.'});
    }
    if (!attrs.feedback) {
        errors.push({name: 'feedback', message: 'Please fill feedback field.'});
    }

    return errors.length &gt; 0 ? errors : false;
}
&lt;/pre&gt;    &lt;p&gt;        Change the `save` method options, to show errors if any error appeared and hide errors if save was successful. &lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var me = this;
var options = {
    success: function () {
        me.hideErrors();
    },
    error: function (model, errors) {
        me.showErrors(errors);
    }
};
&lt;/pre&gt;    &lt;p&gt;        And implement 2 simple methods:&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;showErrors: function(errors) {
    _.each(errors, function (error) {
        var controlGroup = this.$('.' + error.name);
        controlGroup.addClass('error');
        controlGroup.find('.help-inline').text(error.message);
    }, this);
},

hideErrors: function () {
    this.$('.control-group').removeClass('error');
    this.$('.help-inline').text('');
}
&lt;/pre&gt;    &lt;p&gt;        Let's test the code. As all fields are left empty, it will look like,&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh3.googleusercontent.com/-qPbTz5Cl0N4/UJtgc8JU-1I/AAAAAAAALnU/ru1sJb6j6V4/s717/image-2.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh3.googleusercontent.com/-qPbTz5Cl0N4/UJtgc8JU-1I/AAAAAAAALnU/ru1sJb6j6V4/s717/image-2.png"&gt;&lt;/img&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        As fields are filled and form submitted, all errors are cleared from form.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        That was very simple "baby-step" style of approaching model validation. I would could it, validation "from the box". Even if it's very useful there are a lot of different approaches of making even things better. The source code is availble on &lt;a href="https://gist.github.com/4037415"&gt;github&lt;/a&gt;.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Stay tuned for next Backbone.js baby steps soon.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=tk0VzVo6qoM:jGwW4DpYxOQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=tk0VzVo6qoM:jGwW4DpYxOQ:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=tk0VzVo6qoM:jGwW4DpYxOQ:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=tk0VzVo6qoM:jGwW4DpYxOQ:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/tk0VzVo6qoM" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/193781415320351457?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/193781415320351457?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/tk0VzVo6qoM/baby-steps-to-backbonejs-model.html" title="Baby steps to Backbone.js: Model Validation" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh3.googleusercontent.com/-BtV9yCmh3T8/UJtgc5Nk4CI/AAAAAAAALnQ/d671woxZwrE/s72-c/image-1.png" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2012/11/baby-steps-to-backbonejs-model.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkADRHYycCp7ImA9WhNSF0w.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-522385496785822318</id><published>2012-10-31T21:12:00.000+02:00</published><updated>2012-10-31T21:12:55.898+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-10-31T21:12:55.898+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="AJAX" /><title>How to run multiple AJAX requests</title><content type="html">    &lt;p&gt;        Suppose you have a list of resources that you would like to retrieve by means of AJAX. `$.ajax()` (or it's short variants like `$.get()` or `$.post`) is usual way of making AJAX calls, it works great than you need to fetch one.&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var url = '/api/resource/1';
$.get(url, function (r) {
    // use response
});
    &lt;/pre&gt;    &lt;p&gt;        Even in case of several it might be still usable,&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var url1 = '/api/resource/1';
var url2 = '/api/resource/2'
$.get(url1, function (r) {
    // use response from url1

    $.get(url1, function (r) {
        // use response from url2
    });
});
    &lt;/pre&gt;    &lt;p&gt;        You can easily see, if you have more than 3 you are trapping into "callback hell". Furthermore, if you have a list of url's to fetch and the size of that list is dynamic, it's not even possible to build structure like that.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Not long time a ago, I've been exactly into this situation. So, I have a list of resources to fetch, I need to issue them one-by-one and I want to have only one callback, that would pass all fetched resources in one object. Initially I thought it's not even possible, at least with-out creation of some ugly code. But with great help of my colleagues the problem been solved. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        jQuery &lt;a href="http://api.jquery.com/category/deferred-object/"&gt;Deferred Object&lt;/a&gt; is something I've head about, but never got a change to play with. It turn's out to be very nice and simple idea. Deferred allows you to build chainable constructions. Actually, `$.ajax()` always returns deferred object, so you can apply `.done()`, `.fail()` functions on it.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Here is the code, that you could be re-usable in the same situation;&lt;br /&gt;
    &lt;/p&gt;    &lt;pre class="brush: js"&gt;var pipedAjaxRequests = function (urls, callback) {
 var responses = {};

 var promise = $.Deferred().resolve();
 _.each(urls, function (url) {
  promise = promise.pipe(function () {
   return $.get(url);
  }).done(function (response) {
   responses[url] = response;
  });
 });

 promise.done(function () {
  callback(responses);
 }).fail(function (err) {
  callback(responses, err);
 });
};
&lt;/pre&gt;    &lt;p&gt;        It does create the pipe of `$.get()` calls and place the responses in one response object. At the time then all resources are fetched, the callback is called. In case of errors, second parameter of callback will have error info.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Thanks a lot to &lt;a href="http://twitter.com/antsamar"&gt;@antsamar&lt;/a&gt; and &lt;a href="http://twitter.com/alex_gonchar"&gt;@alex_gonchar&lt;/a&gt; for helping me out.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=dXL50EWHKVc:BcQ-tNRWejI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=dXL50EWHKVc:BcQ-tNRWejI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=dXL50EWHKVc:BcQ-tNRWejI:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=dXL50EWHKVc:BcQ-tNRWejI:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/dXL50EWHKVc" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/522385496785822318?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/522385496785822318?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/dXL50EWHKVc/how-to-run-multiple-ajax-requests.html" title="How to run multiple AJAX requests" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/10/how-to-run-multiple-ajax-requests.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIBRHg4fSp7ImA9WhNRE0s.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-7771830389481255241</id><published>2012-10-25T22:40:00.001+03:00</published><updated>2012-11-08T09:42:35.635+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-11-08T09:42:35.635+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><category scheme="http://www.blogger.com/atom/ns#" term="BabyStepsBackbone" /><title>Baby Steps to Backbone.js: Starting up</title><content type="html">    &lt;p&gt;Many times then I speak to people regarding usage of any kind of MV* frameworks on front-end I hear common objection: "but we already have a lot of code written on jQuery/Dojo/Whatever, I think usage of additional framework would be impossible". This is not actually true. Backbone is very lightweight and could fit into any existing application.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Baby steps strategy is the most efficient way of trying the things. You start with something really small, enhance it over the time and expand for other application areas. Now, let's imagine you got an existing application, you wish to start using Backbone.js to improve that. I would like to show you, that it's absolutely possible.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Suppose, you want to add a feedback form for your app. Let's implement that with Backbone.js.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Applications, Models, Views&lt;/h2&gt;&lt;p&gt;There are no such thing as `Controller` in Backbone.js. But you have to have some kind of entry point, some place with `main()` function inside. I got used to call this place - Application. Basically, the application is a module, which is responsible for initialization of model, instantiation of view, rendering the view.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;The `Model` is object that holds the data. It could be fetched and persisted back to server.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;And finally view is object that produces markup, hooking up events and updates View from data in Model and otherwise.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;We are going to create all three things. It makes a lot of sense to breakdown the folder structure of to reflect logical meaning of each entity of Backbone application. So, we'll create 3 folders for apps, models and views.&lt;br /&gt;
&lt;/p&gt;&lt;a href="https://lh5.googleusercontent.com/-aFNqz_2e_i4/UImU8WZaMEI/AAAAAAAAKZ0/-v-Jb5EttRY/s620/image-1.png"&gt;&lt;br /&gt;
&lt;img src="https://lh5.googleusercontent.com/-aFNqz_2e_i4/UImU8WZaMEI/AAAAAAAAKZ0/-v-Jb5EttRY/s620/image-1.png"/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;Setup Backbone.js&lt;/h2&gt;&lt;p&gt;On a target html page we should place 2 additional script tags.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: html"&gt;&amp;lt;script src=&amp;quot;/scripts/libs/underscore.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;/scripts/libs/backbone.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &lt;/pre&gt;&lt;p&gt;Besides of that, let's add one more div. The one that application will be using for rendering views.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: html"&gt;&amp;lt;div id=&amp;quot;app&amp;quot; class=&amp;quot;container&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &lt;/pre&gt;&lt;h2&gt;Application entry point&lt;/h2&gt;&lt;p&gt;Let's create a new file in `apps` folder and call it `FeedbackFormApp.js`. It would be very simple.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;$(function () {
    var model = new Feedback();
    var view = new FeedbackFormView ({model: model});
    
    $('#app').html(view.render().el);
});
    &lt;/pre&gt;&lt;p&gt;Then DOM is ready, we instantiate new model object and view and render the form into DOM element with id - app.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Feedback model&lt;/h2&gt;&lt;p&gt;Now, let's define a model. Create a new file in models folder and call it `Feedback.js`.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;The model refects the data we are collecting/displaying to user and it's typically stored on server (sometimes on localstorage). Feedback model will include 3 attributes: email of user, his web site and the feedback text. In terms of Backbone.js that would mean.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;var Feedback = Backbone.Model.extend({

    url: '/feedback',

    defaults: {
        'email': '',
        'website': '',
        'feedback': ''
    }

});
    &lt;/pre&gt;&lt;p&gt;The &lt;code&gt;url&lt;/code&gt; property of model object is used by Backbone for persisting object to server. The &lt;code&gt;default&lt;/code&gt; are defaults values for model attributes.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Rendering the view&lt;/h2&gt;&lt;p&gt;The most interesting things in Backbone.js app is happening in Views. Add new file to `views` folder - FeedbackView.js.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;The skeleton of view would look like this:&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;var FeedbackFormView = Backbone.View.extend({
   className: 'row',

    render: function () {
        return this;
    }
});
    &lt;/pre&gt;&lt;p&gt;This view, does do nothing. So, let make it render the template. The template would be very simple form.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;There are different approaches, there to actually place the markup. It's possible to place it in the same .html file where view starts and extract it by jQuery, it's possible to place to separate file and load it asynchronously by $.get(). But, according to baby steps scenario - we'll place it directly to .js file. So, inside the view we'll add property called template.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;template: '\
 &amp;lt;form&amp;gt;\
  &amp;lt;legend&amp;gt;Share the feedback&amp;lt;/legend&amp;gt;\
  &amp;lt;div class=&amp;quot;control-group&amp;quot;&amp;gt;\
   &amp;lt;label&amp;gt;Email&amp;lt;/label&amp;gt;\
   &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;email&amp;quot; placeholder=&amp;quot;Your email address...&amp;quot;&amp;gt;\
  &amp;lt;/div&amp;gt;\
  &amp;lt;div class=&amp;quot;control-group&amp;quot;&amp;gt;\
   &amp;lt;label&amp;gt;Web site&amp;lt;/label&amp;gt;\
   &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;website&amp;quot; placeholder=&amp;quot;Your website...&amp;quot;&amp;gt;\
  &amp;lt;/div&amp;gt;\
  &amp;lt;div class=&amp;quot;control-group&amp;quot;&amp;gt;\
  &amp;lt;label&amp;gt;Feedback&amp;lt;/label&amp;gt;\
  &amp;lt;textarea id=&amp;quot;feedback&amp;quot; class=&amp;quot;input-xxlarge&amp;quot; placeholder=&amp;quot;Feedback text...&amp;quot; rows=&amp;quot;6&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;\
  &amp;lt;/div&amp;gt;\
  &amp;lt;button type=&amp;quot;submit&amp;quot; id=&amp;quot;submit&amp;quot; class=&amp;quot;btn&amp;quot;&amp;gt;Submit&amp;lt;/button&amp;gt;\
 &amp;lt;/form&amp;gt;\
',
    &lt;/pre&gt;&lt;p&gt;And render method, would be:&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;render: function () {
    this.$el.html(this.template);

    return this;
}
    &lt;/pre&gt;&lt;h2&gt;First test&lt;/h2&gt;&lt;p&gt;Basically, we are ready to see some results. Modify the target view by adding references to model and view.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: html"&gt;&amp;lt;script src=&amp;quot;/scripts/src/models/Feedback.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;/scripts/src/views/FeedbackFormView.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;/scripts/src/apps/FeedbackFormApp.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &lt;/pre&gt;&lt;p&gt;Fire up the application and go to target page. You should be able to see something like this (for styles I use &lt;a href="http://twitter.github.com/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt; here).&lt;br /&gt;
&lt;/p&gt;&lt;a href="https://lh5.googleusercontent.com/-asgv034ZUyA/UImU8iURcEI/AAAAAAAAKZ4/9Yga2hCy9TQ/s620/image-2.png"&gt;&lt;br /&gt;
&lt;img src="https://lh5.googleusercontent.com/-asgv034ZUyA/UImU8iURcEI/AAAAAAAAKZ4/9Yga2hCy9TQ/s620/image-2.png"/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;If you see the form on screen, it means application started properly.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Submitting the form&lt;/h2&gt;&lt;p&gt;We enter the data into input fields and as soon as data is in-place we are ready to submit. It means we have to catch an event of `Submit` button click and store the model to server.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;To explain to Backbone.js that you interested in particular DOM event, you need to add another property to view. It is called &lt;code&gt;events&lt;/code&gt;.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;events: {
    'click #submit': 'submitClicked'
},
    &lt;/pre&gt;&lt;p&gt;You can read it as - if click happed to element with id `submit`, call function submitClicked.&lt;br /&gt;
&lt;/p&gt;&lt;pre class="brush: js"&gt;submitClicked: function (e) {
    e.preventDefault();

    var options = {
        success: function () {
            alert('Thanks for the feedback!');
        },
        error: function () {
            alert('Opps, your feedback has not been submitted, please try again.');
        }
    };

    var feedback = {
        email: this.$('#email').val(),
        website:  this.$('#website').val(),
        feedback: this.$('#feedback').val()
    };

    this.model.save(feedback, options);
}
&lt;/pre&gt;&lt;p&gt;What it does, is first of all prevent the default behavior of event. So, the form would not be actually posted to server. Second, it prepares the options object's with success and error handlers. After we initialize all attributes with actual values from corresponding inputs/textbox. And finally we call model.save().&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Second test&lt;/h2&gt;&lt;p&gt;Fire up application again. Now, if have properly set-up server side to receive the HTTP post call to `/feedback` you actually post first feedback.&lt;br /&gt;
&lt;/p&gt;&lt;a href="https://lh5.googleusercontent.com/-xoKGopfbwlw/UImU8rspz_I/AAAAAAAAKZ8/8D3bgfnRpgE/s620/image-3.png"&gt;&lt;br /&gt;
&lt;img src="https://lh5.googleusercontent.com/-xoKGopfbwlw/UImU8rspz_I/AAAAAAAAKZ8/8D3bgfnRpgE/s620/image-3.png"/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;From my server trace, I can see that new object is received.&lt;br /&gt;
&lt;/p&gt;&lt;a href="https://lh6.googleusercontent.com/-FPoQZTARH0g/UImU9HR4aHI/AAAAAAAAKaA/fhPj64h6cr8/s621/image-4.png"&gt;&lt;br /&gt;
&lt;img src="https://lh6.googleusercontent.com/-FPoQZTARH0g/UImU9HR4aHI/AAAAAAAAKaA/fhPj64h6cr8/s621/image-4.png"/&gt;&lt;br /&gt;
&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;Now, it's the server job to put to storage, allocate the id etc.&lt;br /&gt;
&lt;/p&gt;&lt;h2&gt;Conclusions&lt;/h2&gt;&lt;p&gt;In this first baby step, I just showed how it's possible to adopt Backbone.js for existing apps. It does not make a lot of sense to re-write your existing code with Backbone.js, but new widgets/elements/applications could be created with Backbone, having a benefit of it's structural approach.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I'll go on with baby steps, showing other features of Backbone.js.&lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=uwIhc6_pXkU:nDp8SNbBz3Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=uwIhc6_pXkU:nDp8SNbBz3Q:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=uwIhc6_pXkU:nDp8SNbBz3Q:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=uwIhc6_pXkU:nDp8SNbBz3Q:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/uwIhc6_pXkU" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7771830389481255241?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/7771830389481255241?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/uwIhc6_pXkU/baby-steps-to-backbonejs-starting-up.html" title="Baby Steps to Backbone.js: Starting up" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh5.googleusercontent.com/-aFNqz_2e_i4/UImU8WZaMEI/AAAAAAAAKZ0/-v-Jb5EttRY/s72-c/image-1.png" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2012/10/baby-steps-to-backbonejs-starting-up.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cCQnc8eip7ImA9WhJaFUQ.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8252321860429473429</id><published>2012-10-05T21:24:00.000+03:00</published><updated>2012-10-07T11:37:43.972+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-10-07T11:37:43.972+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Mind" /><category scheme="http://www.blogger.com/atom/ns#" term="TypeScript" /><title>Looking at TypeScript</title><content type="html">&lt;p&gt;Four days ago my twitter has been nuked. The bomb has exploded after &lt;a href="http://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; site link has reach to top of &lt;a href="http://news.ycombinator.com/item?id=4597716"&gt;Hacker News&lt;/a&gt; and people watched the &lt;a href="http://channel9.msdn.com/posts/Anders-Hejlsberg-Introducing-TypeScript"&gt;video of Anders Hejlsberg&lt;/a&gt; who generally described the language features and showed some example. Everybody were talking about TypeScript.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;For ones who missed the video (I can't believe you did) I shortly describe - TypeScript in new open source project, by Microsoft. It's leader &lt;a href="http://en.wikipedia.org/wiki/Anders_Hejlsberg"&gt;Anders Hejlsberg&lt;/a&gt; is very famous developer (my bad, I always forget his name), creator of C# and one of the persons who most influenced .NET platform. TypeScript compiled down to JavaScript, but it introduce the types checking during compilation, so it could be called 'static typed language'.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;First of all, TypeScript is definitely &lt;a href="https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS"&gt;not the first language&lt;/a&gt;, that complies to JavaScript. It's not the first one that augments JavaScript with new statements like class, interface or module. So, what's so interesting on it?&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I've been using static type languages for about 10 years. I've very much got used to compiler error messages and truly believed that it helps to build applications. Meaning, the complier is first guard towards the 'good' code. To the code that could be called reliable, error free. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;But situation much changed after I start programming JavaScript. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I feel myself quite productive with using of using JavaScript. Of cause, there are some best practice &amp; patters are collected nowadays, we have better tools, faster engines and JavaScript has been so much adopted by community. But JavaScript is indeed, so powerful language. I really like the dynamic typing, that bit more forces to unit testing, making code changes more easy in the same time creating some very beautiful code structures.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;I know that some people are saying, "we don't need any static typing for JavaScript; please don't change the language". Such developers could be called "purists". And they are absolutely right - if you feel confidence in something you do, you should not change the way you do it. &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;In another hand, I came to conclusion that it's not dynamic types that makes me productive with JavaScript, but rather the experience I gathered with programming lately. It's always only experience, that allows you to work faster, better quality and had fun of your job.&lt;br /&gt;
&lt;p&gt;And it's absolutely not about Static vs. Dynamic languages.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Static types are not useless, though. I think, in average it reduces the chances of bug introduction into the code. That's at least what I've seen so far. And that's why "purists" are running JSLint. Basically, Static Types should provide better application quality. This is of cause not completely true, since we know great software written in Python and poor systems written in C++.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;It' about the engineers who build that software.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;In my opinion the TypeScript will grow. It would have it's own army of fans, like CoffeeScript have or Ruby have. The code that TypeScript outputs is nice and clean, that make easy of debugging it. TypeScript is designed to be closer to ECMAScript6 (Harmony), so in near future the pure JavaScript would start to look like TypeScript.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;TypeScript is interesting project and open minded guys will like one. &lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=r2smqDMUrf8:5IXNbJGY03I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=r2smqDMUrf8:5IXNbJGY03I:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=r2smqDMUrf8:5IXNbJGY03I:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=r2smqDMUrf8:5IXNbJGY03I:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/r2smqDMUrf8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8252321860429473429?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8252321860429473429?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/r2smqDMUrf8/typescript-language.html" title="Looking at TypeScript" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/10/typescript-language.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D04GSHY-eip7ImA9WhJbF04.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-6493229755571252544</id><published>2012-09-27T11:52:00.001+03:00</published><updated>2012-09-27T11:52:09.852+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-27T11:52:09.852+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Code Kata" /><category scheme="http://www.blogger.com/atom/ns#" term="Clean Code" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>The Game of Life</title><content type="html">    &lt;p&gt;        Last weekend the good friends of mine were organizing great event, &lt;a href="http://coderetreat.org/"&gt;CodeRetreat&lt;/a&gt; in Odessa. I supposed to be there, but due to bad luck I missed that. Nevertheless, I was very interested in CodeRetreat idea, so I followed up the materials and learned a bit about it. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        CodeRetreat is about the software craftsmanship. You focus on &lt;a href="http://c2.com/cgi/wiki?XpSimplicityRules"&gt;4 principles of Simple Design&lt;/a&gt;, work in pairs through the series of time boxed sessions, each time starting from scratch (yes, all code produced on previous sessions is destroyed with no mercy). All of that aim one simple goal, became a better developer. For the implementation they selected famous &lt;a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life"&gt;Game of Life&lt;/a&gt;. The cellular automata, with simple rules but given very interesting results and foundation for numerous researches.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        To do not stay with my misery of missing event, I decided to "play" game of life at home. Trying to follow the rules of sessions, I started to write some JavaScript code. It's even hard to tell, how much fun I had during this implementation.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Tests, code, tests&lt;/h2&gt;    &lt;p&gt;        TDD is very recommended way of development in CodeRetreats. I love TDD and fortunately the game of life is very TDD friendly. It's all about the logic. Logic seems to be very simple and easy describe with tests. For my JavaScript testing I used to use &lt;a href="http://pivotal.github.com/jasmine/"&gt;Jasmine&lt;/a&gt; testing framework. Jasmine is BDD tests style, which was a little difficult to me at very beginning, but not I tend to write all my tests with BDD style.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I've spent first two sessions for idea elaboration. At the end third session, I got something working. As I said, the process of writing that code was so fun to me, that I even decided to &lt;a href="https://gist.github.com/3763692"&gt;gist&lt;/a&gt; the code I created so far. &lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh6.googleusercontent.com/-bBm_BGTuy1I/UGQSj4MCYCI/AAAAAAAAJfk/m1aRicC5pYY/s622/image-2.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh6.googleusercontent.com/-bBm_BGTuy1I/UGQSj4MCYCI/AAAAAAAAJfk/m1aRicC5pYY/s622/image-2.png" /&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        My big disappointment after was that code is actually not working.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Understanding the problem&lt;/h2&gt;    &lt;p&gt;        Even if I had good tests suite, that showed my code works as expected the game was broken. And the issue is that I didn't understand the domain good enough. It took me 4 sessions (about 4 hours) to finally understand the game.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I proved it once again for myself, there are no perfect code; the code you created at first time is probably broken (unless you understand the domain perfectly, but it's rarely happen in reality). It's OK to completely remove the code you created before and start from the beginning. And with each iteration you moving faster and faster.&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh4.googleusercontent.com/-HYIZR9Ssup4/UGQSj97MsoI/AAAAAAAAJfg/WZSrfAQcyd8/s622/image-3.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh4.googleusercontent.com/-HYIZR9Ssup4/UGQSj97MsoI/AAAAAAAAJfg/WZSrfAQcyd8/s622/image-3.png" /&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        Knowing the requirements I was able to create good test suite. &lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Algorithms and data structures&lt;/h2&gt;    &lt;p&gt;        During the implementation, you have to recall some basics algorithms and data structures. My initial implementation was based on usage of 2-dimensional arrays. It seems to be very natural fit, since the game is happening on orthogonal grid of square cells. But during the implementation of cell replication logic I suffered that design.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Index arithmetic is very tricky and error-prone stuff. So, after several tries I switched from array into the list of cells, each cell holds it's state and position. The &lt;a href="https://github.com/alexanderbeletsky/gameoflife/blob/master/public/js/grid.js#L24"&gt;tick&lt;/a&gt; method of became very elegant, containing 2-pass procedure - one to calculate next state of each state, second is to switch to new state.&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh5.googleusercontent.com/-JvlS1nI_Ay8/UGQSkXu3r-I/AAAAAAAAJfo/slOlEKrDXvo/s622/image-4.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh5.googleusercontent.com/-JvlS1nI_Ay8/UGQSkXu3r-I/AAAAAAAAJfo/slOlEKrDXvo/s622/image-4.png" /&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        Again, I was so happy with code. It looked very readable as for me, without nested cycles and if-else statements.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Visualisation&lt;/h2&gt;    &lt;p&gt;        You can really understand if something works or not, only if you see it in action. I had to have some UI to see, how game is actually working. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I've created very simple HTML based UI. The number of div's which change it's state, depending on cell state (alive or dead).&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh4.googleusercontent.com/-ERo-PofMktc/UGQSjwS4NBI/AAAAAAAAJfc/bOOBADibPGk/s622/image-1.png"&gt;&lt;br /&gt;
        &lt;img src="https://lh4.googleusercontent.com/-ERo-PofMktc/UGQSjwS4NBI/AAAAAAAAJfc/bOOBADibPGk/s622/image-1.png" style="width: 620px" /&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        The visualization of results is very important part. It's only then I tried to run the game on 64x64 square, I realized that performance of my implementation is so terribly poor. It runs very slowly on Chrome, it makes IE10 die.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It means that, all beautiful code, tests, specs and so on - is almost useless, than it comes to performance. My 2-pass algorithm, with a simple implementation is not "production" ready, if we talk about some real software. Unit tests are usually done on smaller sets of data. Visualisation and trying the things on larger set of data opens up the reality.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        As I already said, it's so much fun. It makes you feel like "back to roots", forget about your enterprise stuff and do some real work. Besides it's great TDD exercise. It's probably to big to be called code kata, but it is still great for sharping an axe. Focusing on simple design is important. But making things "visible" and running them in real mode is vital. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        The most important conclusion for me is: I'm still newbie developer, with so many areas to improve.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=oRxRZt45xd8:jBB5xS1mwWg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=oRxRZt45xd8:jBB5xS1mwWg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=oRxRZt45xd8:jBB5xS1mwWg:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=oRxRZt45xd8:jBB5xS1mwWg:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/oRxRZt45xd8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/6493229755571252544?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/6493229755571252544?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/oRxRZt45xd8/the-game-of-life.html" title="The Game of Life" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh6.googleusercontent.com/-bBm_BGTuy1I/UGQSj4MCYCI/AAAAAAAAJfk/m1aRicC5pYY/s72-c/image-2.png" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2012/09/the-game-of-life.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0IEQ347fyp7ImA9WhJbEUk.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8668523858861211425</id><published>2012-09-20T16:58:00.000+03:00</published><updated>2012-09-20T16:58:22.007+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-20T16:58:22.007+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="E-conomic" /><category scheme="http://www.blogger.com/atom/ns#" term="Mind" /><title>Company Days 2012 in E-conomic</title><content type="html">&lt;p&gt;        Company Days is a yearly event in E-conomic, then all employees gather together. It's usually happen in the middle of September, the time than Copenhagen is especially beautiful. It's been great week, primarily because of opportunity to meet guys whom we work very close to. Besides the developers, primarily located in Denmark and Ukraine, business and operational people from UK, Sweden, Norway, Spain, Germany etc. are also coming, so it makes very cool international environment.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        This year was a little special, since we had additional fun. Our CTO had organized the hackathon. The whole day event, supposed to create some valuable hacks for E-conomic product. All developers has been spitted on pairs and extended with business representatives. I had a team of 4 people - 2 developers and 2 business guys. Started at early morning near the blackboard, it was so nice to be part of process where the value is born in such extremely short period. We finally selected the idea, which seems to be very cool in terms of business and realistic in terms of one day implementation.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        It's been a long day of developing, debugging, demonstration and changes. Our product owners were always near us, giving both valuable feedback and supplying us with coffee and Danish chocolate sweets (that worked so good to me, since I needed sugar all the time). About 22.00 we got something that looks like a demo version of feature we wanted to produce. We've spent near 1 hour more, to show everything to PO's and fix some small bugs. I felt very tired at the end.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Next day at 14.00 was big time of presentations. That was the funnies part. I have to admit, there was several really great hacks. In the same time some our PO's are so cool of selling things that they turned the presentation into real show (kind of TV market, I would say). Everybody had a great joy, especially after words like "I've been asking for this feature for 2 year, and those guys created it in 16 hours". It's a bit of irony, but a bit of true as well. I know the jury that included CEO, CTO, Head of PO's etc., we definitely happy to see the results and some hacks will be turned into the products really soon.&lt;br /&gt;
    &lt;/p&gt;    &lt;a href="https://lh6.googleusercontent.com/-LsnSDGvzOrQ/UFsfQmfY5GI/AAAAAAAAJIQ/82qUi0631-A/s720/IMG_5365.JPG"&gt;&lt;br /&gt;
        &lt;img src="https://lh6.googleusercontent.com/-LsnSDGvzOrQ/UFsfQmfY5GI/AAAAAAAAJIQ/82qUi0631-A/s720/IMG_5365.JPG" style="width: 620px" /&gt;&lt;br /&gt;
    &lt;/a&gt;&lt;br /&gt;
    &lt;p&gt;        Apart from the hackathon, we had traditional speeches of CEO, Marketing people and guys from other departments. There was also a bit more activities, including jogging in which I took a part and did 8km distance. And of cause, Friday boat trip and party in restaurant. Party was so cool, that I almost missed my flight in the morning (but that's a completely different story).&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        I would like to say thanks for everybody involved, I was happy to meet you guys once more.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=qe9qXlYEpvQ:N4dCttiDF6I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=qe9qXlYEpvQ:N4dCttiDF6I:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=qe9qXlYEpvQ:N4dCttiDF6I:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=qe9qXlYEpvQ:N4dCttiDF6I:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/qe9qXlYEpvQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8668523858861211425?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8668523858861211425?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/qe9qXlYEpvQ/company-days-2012-in-e-conomic.html" title="Company Days 2012 in E-conomic" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://lh6.googleusercontent.com/-LsnSDGvzOrQ/UFsfQmfY5GI/AAAAAAAAJIQ/82qUi0631-A/s72-c/IMG_5365.JPG" height="72" width="72" /><feedburner:origLink>http://www.beletsky.net/2012/09/company-days-2012-in-e-conomic.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMBRnozcSp7ImA9WhJUGEs.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-2875244855232991339</id><published>2012-09-10T16:36:00.000+03:00</published><updated>2012-09-17T09:14:17.489+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-17T09:14:17.489+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mind" /><title>How My Wife Became a TDD Fan</title><content type="html">&lt;p&gt;My wife, Sasha is not (yet) IT person. Living with developer for 5 years, she knows only few details of developers job (like, they do code and sitting late nights to make it work). My bad, I never spent much time to explain what really my job is.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Recently she joined the training courses on software testing, to find the job in IT area in perspective.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;After her second lesson she got back home and we had a talk about what she is actually studying there. It appeared they started with a software development processes, understanding how the software is actually created. So, they described waterfall (even if  nobody using it any more) and some agile frameworks (scrum of cause), and left with a homework, to read what else practices exists.&lt;br /&gt;
&lt;/p&gt;&lt;blockquote&gt;- So, did you find anything interesting?&lt;br /&gt;
- I read about few, but I think I found the most interesting one..&lt;br /&gt;
- What's that?&lt;br /&gt;
- Its called Extreme Programming..&lt;br /&gt;
- Hm, I never heard about it. Tell me more (trolls face on).&lt;br /&gt;
- Alright, so it's a different practices as Code review, Pair programming, Collective code ownership.. But you know, what's the greatest one?&lt;br /&gt;
- No, what's that?&lt;br /&gt;
- Its called Test Driven Development, or TDD.&lt;br /&gt;
- What's the point of this TDD? (troll face is still on).&lt;br /&gt;
- Can you imagine that you create the test before you create any application code, make sure it doesn't work and after you fix it, so you always sure that application works fine! That's sound so interesting and so valuable, I can't wait to try it!&lt;br /&gt;
&lt;/blockquote&gt;&lt;p&gt;I had to put my troll face off, after that. I could not believe what I'm hearing. That was simply amazing!&lt;br /&gt;
&lt;/p&gt;&lt;blockquote&gt;- Do you know, I'm a big TDD fan and the training courses I do from time to time are "TDD in .NET", so we teach people of using TDD practices in real projects.&lt;br /&gt;
- Fantastic, I never thought your job is so interesting!&lt;br /&gt;
&lt;/blockquote&gt;&lt;p&gt;The big disappointment to her was that testers are not doing TDD (she though it's actually the testers job). Nethertheless, I got one interesting thought.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;During the trainings on TDD we try hard to explain people the value of TDD and usually there some guys who just deny the idea, seeing absolutely no value in it. That actually show some human feature called "open mindness". &lt;br /&gt;
&lt;/p&gt;&lt;p&gt;As less you know, as easy to you to get new ideas.. As much you know, as less agile your brain could be, as hard you can adopt anything new.With more experience you got, it's harder and harder to adopt new things. This is only the matter of discipline and hard working to stay update and actually try things out. It's also a big patience till some tool or technique became beneficial to you.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;The point of my story is. Developer have to be open minded person during whole career. Something you did yesterday, may became obsolete tomorrow. There are many things outside your comfort zone you might missing, staying in comfort zone for long time.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;Back to Sasha, I always knew she is very bright lady. Now I hope she became bright engineer, good luck to you, honey.&lt;br /&gt;
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=3754e4UT5iw:olZ9b2y5yu0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=3754e4UT5iw:olZ9b2y5yu0:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=3754e4UT5iw:olZ9b2y5yu0:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=3754e4UT5iw:olZ9b2y5yu0:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/3754e4UT5iw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/2875244855232991339?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/2875244855232991339?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/3754e4UT5iw/how-my-wife-bacame-tdd-fan.html" title="How My Wife Became a TDD Fan" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/09/how-my-wife-bacame-tdd-fan.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08ESXYyeip7ImA9WhJUEE4.&quot;"><id>tag:blogger.com,1999:blog-3980660135707078299.post-8736369806854386635</id><published>2012-09-07T18:30:00.000+03:00</published><updated>2012-09-07T18:30:08.892+03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-09-07T18:30:08.892+03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="Backbone.js" /><title>Why Use Backbone.js?</title><content type="html">    &lt;p&gt;        Even JavaScript language and front-end development has been much matured recent time, I still see a lot of confusion about usage of different frameworks and libraries.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        For a half of year I use Backbone.js and feel much satisfied with it. It's very popular library, probably because of personal popularity of the creator of Backbone.js &lt;a href="http://en.twitter.com/jashkenas"&gt;Jeremy Ashkenas&lt;/a&gt;, very much known also as author of CoffeScript language.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Frameworks and libraries&lt;/h2&gt;    &lt;p&gt;        There are differences between frameworks and libraries. In one sentence, "library is then you call some code, framework is then your code is called from somewhere". The Backbone.js is clearly library. You usually have a lot of different options with libraries and less with frameworks. It's very minimalistic, actually.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        At core it only contains of only 4 components (Model, Collection, View, Router). This minimalism is both power and weak side of Backbone.js. The power is that you can build things whatever you like, Backbone fits the experience really smoothly. In the same time, you are really confused the time you just started, since you simply don't understand how to make everything work together properly.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;The essence of Backbone.js&lt;/h2&gt;    &lt;p&gt;        In one of the podcasts with Jeremy, he said "Backbone is something that almost every developer will come to theirselves.. dealing with JavaScript applications for a while". I could not agree more. If you have previous experience in programming and you see the value of architecture and design, you will definitely start to invent something similar to Backbone.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        After some time spend of development jQuery based application you will realize many fundamental issues, like: data does not belong to DOM, events are not limited on jQuery and so on. But the main issue is jQuery apps usually violates the "Single Responsibility Principle", mixing and manipulation with data and views in the same time. Experienced developers, tries to eliminate SRP issues as soon as possible, almost naturally coming to MVC pattern.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        In essence the Backbone is a way to structure you application better. It makes clear de-coupling between data and views that render that data. It's nothing more than that.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Abstracting things out&lt;/h2&gt;    &lt;p&gt;        Programming is a matter of abstractions. As better abstractions you have as better code you have. &lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        Every application works with data. The data does not appear in browser just like that, it have to fetched from somewhere. It's also have to be persisted somewhere. The data could be changed and you have to validate that change is right. If some part of data is changing, you want to be notified on that change. Notice that, this is a very common functionality you want to keep between all data classes - initialization, validation, persistence. This is where the &lt;code&gt;Backbone.Model&lt;/code&gt; comes out. With &lt;code&gt;Backbone.Model&lt;/code&gt; all that things are already "in the box" you just need to apply your own strategies of implementation.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        You typically don't deal with one instance of model. REST interfaces are usually expose something like &lt;code&gt;/api/tasks&lt;/code&gt; or &lt;code&gt;/api/photos&lt;/code&gt; and so on. You need to group the models into collections. Collection (similar to model) are able fetch and persist itself, all it needs to know is the actual type of Model and URL. This is where &lt;code&gt;Backbone.Collection&lt;/code&gt; shies. You are keeping all models close together, if some model become destroyed the collection will be updated, so it always in consistent state.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        With view is basically render your models as DOM structure. So, the &lt;code&gt;Backbone.View&lt;/code&gt; is abstraction with primarily method - &lt;code&gt;render&lt;/code&gt;. Backbone does not say, how exactly you are going to do that. You can create handcrafted HTML and append it DOM, or use some templating mechanisms. Instead, it provides you convenient methods for listening to view events (like clicks, focusout or any other DOM supported events). Inside the handlers you either could update related model or apply some changes to view parts, whatever.&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        And finally &lt;code&gt;Backbone.Router&lt;/code&gt; is a facility to building, so called Single Page Applications (SPA). SPA's most popular example is GMail. You browsing emails, writing and sending - without and page reloads. What's changing is only hash part of URL (like #inbox, #sent, #all). Router is handling hash change events and triggers registered handler. Inside the handler, you can initialize the corresponding application.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Don't repeat yourself&lt;/h2&gt;    &lt;p&gt;        Now, please let me know. How many times did you create (read copy-n-paste) the code for RESTful data persistence? How many times, you did you create code for validation? How many hours you spend for looking for some event listener provoking the bug in your app and hiding somewhere among 200 .js files?&lt;br /&gt;
    &lt;/p&gt;    &lt;p&gt;        If your answer, more that 2 - stop doing that. Don't repeat yourself - reuse. And better - reuse from best.&lt;br /&gt;
    &lt;/p&gt;    &lt;h2&gt;Conclusions&lt;/h2&gt;    &lt;p&gt;        There are great solutions, created by people experienced than me, amplified by huge community behind. &lt;a href="https://github.com/documentcloud/backbone"&gt;Backbone.js&lt;/a&gt; is one best representatives of such solutions. Having a something that I could rely on, that works good and there &lt;a href="http://stackoverflow.com/questions/tagged/backbone.js"&gt;places&lt;/a&gt; to get help is very strong reason for me, to keep doing that, instead of re-invent wheel yet another time.&lt;br /&gt;
    &lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=CEDCZg3cBvQ:rqPIxBuLrh4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=CEDCZg3cBvQ:rqPIxBuLrh4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/abeletskyblog?a=CEDCZg3cBvQ:rqPIxBuLrh4:-BTjWOF_DHI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/abeletskyblog?i=CEDCZg3cBvQ:rqPIxBuLrh4:-BTjWOF_DHI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/abeletskyblog/~4/CEDCZg3cBvQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8736369806854386635?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/3980660135707078299/posts/default/8736369806854386635?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/abeletskyblog/~3/CEDCZg3cBvQ/why-use-backbonejs.html" title="Why Use Backbone.js?" /><author><name>Alexander Beletsky</name><uri>https://plus.google.com/104123427697898813533</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh5.googleusercontent.com/-WqHPxmC8QfM/AAAAAAAAAAI/AAAAAAAAOBo/VVeQKGSrJ5Q/s512-c/photo.jpg" /></author><feedburner:origLink>http://www.beletsky.net/2012/09/why-use-backbonejs.html</feedburner:origLink></entry></feed>
