tag:blogger.com,1999:blog-81580599907408216092009-07-13T05:43:51.173+03:00Running & Coding"Good artists copy, great artists steal." Pablo Picassodor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.comBlogger19125tag:blogger.com,1999:blog-8158059990740821609.post-49656079107719298882009-06-10T01:12:00.013+03:002009-06-10T11:32:31.700+03:00Erlang Riddle for Rubists<div>The next "Erlang made stupid simple for Ruby programmers" post & screencast is in the making. I am reading again and again the pages of <a href="http://www.amazon.com/dp/193435600X?tag=rc08b-20&camp=14573&creative=327641&linkCode=as1&creativeASIN=193435600X&adid=1YBMFVQR2YS59NKFQGMT&">Software for a Concurrent World</a> and try to synthesize Erlang's essence for the "average" Rubist.</div><div><br /></div><div>Some stuff is straight forward, like <b>Fun</b>s which is the Erlang Funny name for Anonymous functions.</div><div><br /></div><div>ERLANG:</div><div><br /></div><div><div><div><div><span class="Apple-style-span" style="font-family:'courier new';">1> Z = fun(X) -> 2*X end.</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">#Fun<erl_eval.6.13229925></erl_eval.6.13229925></span></div><div><span class="Apple-style-span" style="font-family:'courier new';">2> Z(2). </span></div><div><span class="Apple-style-span" style="font-family:'courier new';">4</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">3> Double = Z.</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">#Fun<erl_eval.6.13229925></erl_eval.6.13229925></span></div><div><span class="Apple-style-span" style="font-family:'courier new';">4> Double(4). </span></div><div><span class="Apple-style-span" style="font-family:'courier new';">8</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">5> Double(4). </span></div><div><span class="Apple-style-span" style="font-family:'courier new';">8</span></div><div></div></div><div><br /></div><div>RUBY:</div><div><br /></div><div><div><div><span class="Apple-style-span" style="font-family:'courier new';">irb(main):004:0> Z = Proc.new { |x| x*2 }</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">=> #<proc:0x010145cc@(irb):4></proc:0x010145cc@(irb):4></span></div><div><span class="Apple-style-span" style="font-family:'courier new';">irb(main):005:0> Z.call(2)</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">=> 4</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">irb(main):006:0> Double = Z</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">=> #<proc:0x010145cc@(irb):4></proc:0x010145cc@(irb):4></span></div><div><span class="Apple-style-span" style="font-family:'courier new';">irb(main):007:0> Double.call(2)</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">=> 4</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><br /></span></div><div></div></div><div>Great stuff, never had to use it in Ruby - but maybe in Erlang it might serve me, who knows....</div></div></div></div><div><br /></div><div>Now that is an easy one. Later in the book, Joe Armstrong gives an example of a function that returns all <a href="http://www.regentsprep.org/rEGENTS/math/permut/Lperm.htm">permutations</a> of a given string.</div><div><br /></div><div><div><div><span class="Apple-style-span" style="font-family:'courier new';"><div><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-style-span" style="font-size:small;">perms([]) -> [[]]; </span></span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-style-span" style="font-size:small;">perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])].</span></span></div><div></div></span></div><div><br /></div><div>I have tried to rewrite it in Ruby, in a form that would mostly imitate what's done here.</div><div>That's my best try so far:</div><div><br /></div><div><div><span class="Apple-style-span" style="font-family:'courier new';"><div><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-style-span" style="font-size:small;">def prem(s,nx = [])</span></span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-tab-span" style="white-space:pre"><span class="Apple-style-span" style="font-size:small;"> </span></span><span class="Apple-style-span" style="font-size:small;">return nx.join if s.empty?</span></span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-tab-span" style="white-space:pre"><span class="Apple-style-span" style="font-size:small;"> </span></span><span class="Apple-style-span" style="font-size:small;">s.collect { |b| prem(s-[b],nx+[b]) }.flatten</span></span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-style-span" style="font-size:small;">end</span></span></div><div><span class="Apple-style-span" style="font-family:'courier new';"><br /></span></div><div><span class="Apple-style-span" style="font-family:'courier new';">puts prem('dor'.split(//))</span></div><div><br /></div><div><div><b>output:</b></div><div><br /></div><div>dor</div><div>dro</div><div>odr</div><div>ord</div><div>rdo</div><div>rod</div><div><br /></div></div><div></div></span></div><div>I hate the flatten hack I did there to simulate Erlang's valuse return as one Array.</div><div>I dislike having to send prem all his recursive "past" (as "nx").</div><div><br /></div><div><b><span class="Apple-style-span" style="color:#660000;">I think there must be a better way to do it. A better way that will deliver the Erlangian concepts.</span></b></div><div><b><span class="Apple-style-span" style="color:#660000;">Do you think you might have a better way to pronounce the Erlangian magic of this function in Rubish ? If so, please post it here (as a comment) I'd really love to see it!</span></b></div><div><span class="Apple-style-span" style="color:#660000;"><br /></span></div><div><span class="Apple-style-span" style="color:#000099;"><b>Whoever has a better solution (me need to like) will get full credits and endless honor (!)</b></span></div></div></div></div><br /><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 360px; height: 451px;" src="http://gamesmuseum.uwaterloo.ca/VirtualExhibits/puzzles/language/riddler.jpg" border="0" alt="" /><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-4965607910771929888?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com1tag:blogger.com,1999:blog-8158059990740821609.post-11931934419386966862009-06-06T22:41:00.003+03:002009-06-06T22:45:54.277+03:00The Screencast: Erlang made stupid simple for Ruby programmers<div><span class="Apple-style-span" style="color:#000099;"><a href="http://www.dorkalev.com/2009/05/erlang-made-stupid-simple-for-ruby.html">Erlang made stupid simple for Ruby programmers</a> receives traffic well beyond my expectations. I therefore went forward and created it as a screencast:</span></div><div><br /><object width="400" height="300"><param name="allowfullscreen" value="true"><param name="allowscriptaccess" value="always"><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=5034689&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1"><embed src="http://vimeo.com/moogaloop.swf?clip_id=5034689&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-1193193441938696686?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com2tag:blogger.com,1999:blog-8158059990740821609.post-58681835032451310222009-05-30T21:31:00.014+03:002009-06-10T01:20:23.674+03:00Erlang made stupid simple for Ruby programmers<div><b><span class="Apple-style-span" style="color:#000066;">Update:</span> This post has amazing traffic so it now has its own </b><a href="http://www.dorkalev.com/2009/06/screencast-erlang-made-stupid-simple.html"><b>screencast</b></a></div><div><br /></div><div>I have a strong gut feeling that Erlang is the next (current) big thing.</div><div><div><div><div><br /></div><div>I started learning erlang with the very good and well written book by Joe Armstrong, <a href="http://www.amazon.com/dp/193435600X?tag=rc08b-20&camp=14573&creative=327641&linkCode=as1&creativeASIN=193435600X&adid=1YBMFVQR2YS59NKFQGMT&">Programming Erlang: Software for a Concurrent world</a> . I am trying to keep a summary of what I am learning and so I started writing it as a little note. Doing so I noticed that I am able to squeeze a lot of pages into few lines and thought that someone else apart from me MIGHT also understand what I meant as I wrote it as if I was explaining Erlang to another Rubist. I hope I am right.</div><div><br /></div><div>* I have tried to remain superficial and not to get into details in order to keep things as simple as possible to start with.</div><div><br /></div><div>The list is here, I might also produce a small screen cast and part #2 for this in the coming future. Enjoy!</div><div><br /><ul><li> end every sentence with a dot.</li><br /><li> you can write numbers with base declaration: BASE#NUMBER.<br />example: 15 is like 10#15 or 16#f</li><br /><li> erlang has no variables, only constants.</li><br /><li> erlang's constants are being called variables.</li><br /><li> constants start with a capital letter:<br /><span class="Apple-style-span" style="font-family:'courier new';"> C = 5.<br />CapitalLetter = 5.</span></li><br /><li> divide floats with "/"<br /><span class="Apple-style-span" style="font-family:'courier new';"> 5 / 3 => 1.6667<br />5.25 / 3 => 1.75</span></li><br /><li> divide integer with "div"<br /><span class="Apple-style-span" style="font-family:'courier new';"> 5 div 3 => 1</span></li><br /><li> modulo = reminder = "rem"<br /><span class="Apple-style-span" style="font-family:'courier new';"> 5 rem 3 => 2</span></li><br /><li> "string" is written with double-quotes</li><br /><li> atom = ruby :symbol is written as is (starts only with lowercase letter)<br /><span class="Apple-style-span" style="font-family:'courier new';"> johnny_walker </span></li><br /><li> 'something' acts different then "something" or symbol. still need to figure it out.</li><br /><li>kind of array = tuple<br />defined with {}<br />used broadly in erlang, also to replace complex data structures you would create a class for in ruby.<br /><span class="Apple-style-span" style="font-family:'courier new';"> NiceTuple = { 10, 45 }.<br />NicerTuple = { 10, joe, 45, david }.</span></li><br /><li> {X,Y,Z} = {1,2,3}.<br />X => 1<br />Y => 2<br />Z => 3<br />like multiple assignment in ruby:<br />x,y,z = 1,2,3<br />it works just the same in these cases.</li><br /><li><span class="Apple-style-span" style="font-family:'courier new';"> {something,X} = {something,5}.<br />x => 5</span><br />BUT<br /><span class="Apple-style-span" style="font-family:'courier new';"> {something,X} = {something_else,5}.<br /></span> wont set X (!)<br />"=" sets if left tuple structure fits right tuple structures in length and position of atoms/strings.<br /><span class="Apple-style-span" style="font-family:'courier new';"> {"gran torino",X} = {"gran torino",5}.<br />X => 5</span></li><br /><li> err: {something,X,X,X} = {something,1,2,3}.</li><br /><li><span class="Apple-style-span" style="font-family:'courier new';"> {_,_,_,koko,5,X,_,_} = {i,dont,care,koko,5,123,whats,here}.<br />X => 123</span></li><br /><li> arrays on steroids = lists<br />defined with []<br /><span class="Apple-style-span" style="font-family:'courier new';"> [1,2,3,[4,5]]<br />[i,ate,{a,tasty,cake}]</span></li><br /><li><span class="Apple-style-span" style="font-family:'courier new';"> SmallArray = [3,4].<br />BigArray = [1,2|SmallArray].<br />BigArray => [1,2,3,4].</span></li><br /><li><span class="Apple-style-span" style="font-family:'courier new';"> [First_element|All_the_rest] = Array.<br />[First_element|All_the_rest] = [1,2,3,4,5].<br />First_element => 1<br />All_the_rest => [2,3,4,5]</span></li><br /><li><span class="Apple-style-span" style="font-family:'courier new';"> [First,Second,Third|All_the_rest] = Array.<br />[First,Second,Third|All_the_rest] = [1,2,3,4,5,6].<br />First => 1<br />Second => 2<br />Third => 3<br />All_the_rest = [4,5,6].</span></li><br /><li><span class="Apple-style-span" style="font-family:'courier new';"> {X,Y,Z} = {1,koko,"loko"}.<br />X => 1<br />Y => koko<br />Z => "loko"</span></li><br /><li> modules: Erlang's basic unit structure, comes in a file<br />filename.erl<br />erlang compiles it and then its called<br />filename.beam</li><br /><li> the structure of a .erl file:<br /><span class="Apple-style-span" style="font-family:'courier new';"> -module(file_name).<br />-export([function_name/1]).<br /><br />function_name(X) -> 0.</span><br />---------------------------<br />this amazing module should then be called from the erl console with<br /><span class="Apple-style-span" style="font-family:'courier new';"> c(file_name)<br /></span> and then<br /><span class="Apple-style-span" style="font-family:'courier new';"> file_name:function_name(1) => 0<br />file_name:function_name(koko) => 0<br />file_name:function_name(whatever) => 0</span></li><br /><li> a more interesting function:<br /><span class="Apple-style-span" style="font-family:'courier new';"> -module(file_name).<br />-export([function_name/1]).<br /><br />function_name(true) -> 'funny';<br />function_name(false) -> 'not funny'.</span><br />-----------------------------<br />this function returns different values for "true" and for "false"</li><br /><li> one nicer example:<br /><span class="Apple-style-span" style="font-family:'courier new';"> -module(file_name).<br />-export([fib/1]).<br /><br />fib(0) -> 0;<br />fib(1) -> 1;<br />fib(N) -> fib(N-1) + fib(N-2).</span></li></ul>to be continued ...<br /></div></div></div></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-5868183503245131022?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com2tag:blogger.com,1999:blog-8158059990740821609.post-74628106923236119662009-02-16T07:46:00.013+02:002009-02-16T14:33:52.867+02:00Big oaks from little acorns growI usually focus on programming and the internet world on this blog.<br />Though I have a lot to say about politics in Israel and in general, I usually avoid this topic, knowing that listening to a different opinion on this is a very rare commodity for those who are emotionally involved. And we all are deeply emotionally involved - Jews, Muslims, Christians, Atheists and other...<br /><br />Yet I think there's an idea that most of us are not yet involved deeply enough with, that is worth mentioning in these wicked days.<br /><br />I saw an article in the paper today that some UN committee foresees 50 million jobs to be lost in 2009. 50,000,000 people will lose their jobs. That's a lot.<br /><br />What I find more interesting is (1) I can't recall who really said it (UN committee? what does that mean?) (2) I can't recall if they meant 50,000,000 jobs lost, or that there will be 50,000,000 unemployed people in the western world (no one really knows what happens in Africa, right?)<br /><br />Since the newspaper article didn't go into these details and we're left with just this perspective, they might as well just have written in the paper "BE AFRAID." It would have the same effect.<br /><br />Yet it is also true that old people are losing their pensions, and that too many family people find themselves with debts and with no income.<br /><br />In such times what's growing more than anything else is a sense of fear and uncertainty - and with that grows the need for strength and certainty (it's a simple equation). In pursuit of <b>strength and certainty</b>, it's so easy to slip into confusion and misunderstanding.<br /><br /><b>Strength and certainty are not to be found externally.</b> These are inner sources of belief and hope that can give one the strength to go on and actually achieve something in a land of psychological depression and common moral depression.<br /><br />Remember: There's still a lot of money in the system and plenty of ways to maintain a decent quality of life.<br /><br /><b>What should we be scared about?</b><div><br /></div><div>Looking for the strength and certainty <b>externally</b> - in the form of a "Strong Leader" or a "Strong System of Ideas and Ideals" that claims to be so right that we must follow him/her/it, as that promises us Heaven's Joy Here on Earth (or in other life...).<br /><br />We do need strong leaders and a strong systems of ideas and ideals that can lead people safely through this crisis. But this is a peripheral part of the equation.<br /><br />Strength is not necessarily the action of force and power. There is amazing strength in silence and tolerance, in compassion and understanding and in NOT-RESPONDING - taking 5 more minutes to think.<br /><br />It is time to go inside and outside. Finding <b>inspiration</b> inside and outside, in nature's work or in spiritual places (whatever your belief is or is not).<br /><br /><img style="float:left; margin:0 10px 10px 0;width: 200px; height: 195px;" src="http://1.bp.blogspot.com/_4IC8U7ueZEs/SZkGqjybIYI/AAAAAAAAAGY/4QQ-dwlQUSo/s200/Picture+4.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5303277364436476290" />As the waves and winds get stronger and higher, those who are calmer and are "fast on the inside and slow on the outside" will be able to pass through this crisis and remain intact.<br /><br />Look for the stronger leader - within.<br /></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-7462810692323611966?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com3tag:blogger.com,1999:blog-8158059990740821609.post-7889908220582778132008-07-07T02:54:00.007+03:002008-07-07T03:14:31.641+03:00PAW!!!<div style="clear:both"><br /></div><br /><div><a href="http://pawst.com/">http://pawst.com</a></div><div><br /></div><div>A search engine that reminds google's "I Feel Lucky", they call it PAW!</div><div><br /></div><div>you write a subject and PAW! for it, it will show you the TITLE of a found webpage and will load it.</div><div><br /></div><div>clicking PAW! again will move you to the next search result.</div><div><br /></div><div>SO, WHAT'S SO COOL ABOUT IT ???</div><div><br /></div><div>THE RESULTS ARE GREAT!!! I found myself surfing from website to website and revealing wonderful websites along the way!</div><div><br /></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-788990822058277813?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-70515105642649646142008-04-11T01:05:00.021+03:002008-04-20T19:28:26.862+03:00Juggernaut, an up-to-date tutorialApril 20 - posted a fix to chapter 9:<br /><ol><li>Make sure you have all the prerequisites installed:<br /><br />Rails 2.0.2 or edge<br />Json gem (gem install json)<br />EventMachine gem (gem install eventmachine)<br /><br /></li><li>Install the GEM -<br /><pre>sudo gem install juggernaut</pre></li><li>Create a new Rails APP -<br /><pre>rails koko</pre></li><li>Enter it's dir -<br /><pre>cd koko<br /></pre></li><li>Install the Juggernaut plugin -<br /><pre>ruby script/plugin install<br /><a href="http://juggernaut.rubyforge.org/svn/trunk/juggernaut">http://juggernaut.rubyforge.org/svn/trunk/juggernaut</a></pre></li><li>Paste this inside koko/juggernaut.yml -<br /><br /><span style="font-style: italic;"><a href="http://pastie.caboo.se/179083">http://pastie.caboo.se/179083 </a></span><br /><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_4IC8U7ueZEs/R_87CVB9SzI/AAAAAAAAADw/cEvbaOYT2LU/s1600-h/Picture+8.png"><img id="BLOGGER_PHOTO_ID_5187930206945233714" style="clear: both; cursor: pointer;" alt="" src="http://bp3.blogger.com/_4IC8U7ueZEs/R_87CVB9SzI/AAAAAAAAADw/cEvbaOYT2LU/s400/Picture+8.png" border="0" /></a><br /></div><br /></li><li>Paste this inside koko/config/juggernaut_hosts.yml -<br /><br /><span style="font-style: italic;"><a href="http://pastie.caboo.se/179077">http://pastie.caboo.se/179077 </a></span><br /><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R_84w1B9SwI/AAAAAAAAADY/ql-VXGZlr-g/s1600-h/Picture+5.png"><img id="BLOGGER_PHOTO_ID_5187927707274267394" style="clear: both; cursor: pointer;" alt="" src="http://bp1.blogger.com/_4IC8U7ueZEs/R_84w1B9SwI/AAAAAAAAADY/ql-VXGZlr-g/s400/Picture+5.png" border="0" /></a><br /></div><br /></li><li>Paste this inside koko/app/controllers/chat_controller.rb -<br /><br /><span style="font-style: italic;"><a href="http://pastie.caboo.se/179079">http://pastie.caboo.se/179079</a></span><br /><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R_86A1B9SyI/AAAAAAAAADo/Ge1xQi8FvX8/s1600-h/Picture+6.png"><img id="BLOGGER_PHOTO_ID_5187929081663802146" style="clear: both; cursor: pointer;" alt="" src="http://bp1.blogger.com/_4IC8U7ueZEs/R_86A1B9SyI/AAAAAAAAADo/Ge1xQi8FvX8/s400/Picture+6.png" border="0" /></a><br /></div><br /></li><li>Paste this inside <span style="font-weight: bold;">koko/app/views/chat/index.rhtml</span> -<br /><br /><span style="font-style: italic;"><a href="http://pastie.caboo.se/179073">http://pastie.caboo.se/179073</a></span><br /><br /><div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R_85V1B9SxI/AAAAAAAAADg/DlMEGyBQ5J8/s1600-h/Picture+4.png"><img id="BLOGGER_PHOTO_ID_5187928342929427218" style="clear: both; width: 309px; cursor: pointer; height: 157px;" alt="" src="http://bp1.blogger.com/_4IC8U7ueZEs/R_85V1B9SxI/AAAAAAAAADg/DlMEGyBQ5J8/s400/Picture+4.png" border="0" /><br /></a></div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R_85V1B9SxI/AAAAAAAAADg/DlMEGyBQ5J8/s1600-h/Picture+4.png"><br /></a></li><li>*FOR UBUNTU ONLY (and maybe other linux distors too):<br /><pre><span><span style="font-family:Georgia,serif;">export PATH=$PATH:/var/lib/gems/1.8/bin</span></span></pre> (add it to your bash.profile too)<br />or use /var/lib/gems/1.8/bin/juggernaut in the next phase<br /><br /></li><li>Run the Juggernaut Server -<br /><pre>juggernaut -c juggernaut.yml<br /><span style="font-family:Georgia,serif;"><br />"Starting Juggernaut server on port: 5001..." is the answer you than expect<br /></span></pre></li><li><span style="font-family:Georgia,serif;">Run the Rails Server -<br /></span><pre>script/server<span style="font-family:Georgia,serif;"></span></pre></li><li><span style="font-family:Georgia,serif;">Browse to -<br /><br /><span style="font-style: italic;">http://localhost:3002/chat?send_to_channel=1&listen_to_channel=1</span><br /><br /></span><div style="text-align: center;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_4IC8U7ueZEs/R_8-dlB9S1I/AAAAAAAAAEA/D7wEBWXun8k/s1600-h/Picture+12.png"><img id="BLOGGER_PHOTO_ID_5187933973631552338" style="clear: both; width: 287px; cursor: pointer; height: 280px;" alt="" src="http://bp0.blogger.com/_4IC8U7ueZEs/R_8-dlB9S1I/AAAAAAAAAEA/D7wEBWXun8k/s400/Picture+12.png" border="0" /></a></div><br /><span style="font-family:Georgia,serif;">You will be sending and receiving through the channel numbers specified in the QueryString<br /><br />You can use either "RAILS SEND" to send through the Rails Server or "JS SEND" to use the Ruby Server only ( YES - it will work with your Rails server down)<br /><br />Notice that I've "faked" a firebug-like console on the right, to see all Juggernaut logs in realtime even if you're not using firebug.<br /><br />The input from the listened-to channel is shown on the left box.<br /><br /></span>Now, open another browser with the same URI and start chatting!<br /><div><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R_9AA1B9S2I/AAAAAAAAAEI/_bMenMAgEto/s1600-h/Picture+14.png"><img id="BLOGGER_PHOTO_ID_5187935678733568866" style="clear: both; width: 328px; cursor: pointer; height: 161px;" alt="" src="http://bp1.blogger.com/_4IC8U7ueZEs/R_9AA1B9S2I/AAAAAAAAAEI/_bMenMAgEto/s400/Picture+14.png" border="0" /></a><br /></div><br /></li></ol>ENJOY!<br /><br /><br /><br />Resources:<br /><a href="http://juggernaut.rubyforge.org/">http://juggernaut.rubyforge.org/</a><br /><a href="http://groups.google.com/group/Juggernaut-for-Rails">http://groups.google.com/group/Juggernaut-for-Rails</a><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-7051510564264964614?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com18tag:blogger.com,1999:blog-8158059990740821609.post-91820275075405373092008-04-11T00:17:00.006+03:002008-04-12T00:43:12.852+03:00Juggernaut, Push Server, The future of the webMy dear blog, it's been 3 long month since my last post. Forgive me.<br />I had so many stuff to do:<br /><br /><ul><li>Coding - have you seen the new forums at SA? (<a href="http://seekingalpha.com/symbol/aapl/mb/topics">http://seekingalpha.com/symbol/aapl/mb/topics</a>)<br />Kudos to everyone in SA tech team<br /></li><li>Running</li><li>Learning Italian</li><li>A little more ...</li></ul>But than - suddenly, unexpectedly, I ran across... The next hottest thing in WEB - <a href="http://juggernaut.rubyforge.org/">JUGGERNAUT</a>!<br /><br /><br /><div style="TEXT-ALIGN: left">Yes, treat it as the new Gospel in our business... web.<br /></div><ol><li><span style="FONT-WEIGHT: bold">What is it?</span></li><li><span style="FONT-WEIGHT: bold">What's new? we had it since ever!</span></li><li><span style="FONT-WEIGHT: bold">How will it change the web?</span></li><li><span style="FONT-WEIGHT: bold">How can I start?</span></li></ol><span style="FONT-WEIGHT: bold">1. What is it?</span><br /><br /><p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.thesuperheroquiz.com/villain/pics/juggernaut.jpg"><img style="CLEAR: both; DISPLAY: block; FLOAT: left; MARGIN: 10px; WIDTH: 116px; CURSOR: pointer; HEIGHT: 148px; TEXT-ALIGN: left" alt="" src="http://www.thesuperheroquiz.com/villain/pics/juggernaut.jpg" border="0" /></a><br />It's more than Ajax.<br />Ajax is an HTTP connection that's opened especially per request and closes as it ends.<br />Juggernaut, with Flash OBJECT on the Client Side and Ruby Server (<a href="http://en.wikipedia.org/wiki/Push_technology">Push Server</a>) on the Server Side, allows you to keep an open connection and thus allow real-time connection.<br /><br /><span style="FONT-WEIGHT: bold"><br /><br />YU HU!!! what's so amazing about it?</span>??<br /><br />Very high frequency (on my machine ~ 2000 req/second)<br />Scalability (based on EventMachine)<br />Low Hosting Costs (less servers and memory is needed than if Ajax was used)<br /><br /><span style="FONT-WEIGHT: bold">2. What's new? we had it since ever!</span><br /><br />Juggernaut does it well, easy, cheap and smart.<br /><br />Client Side: JavaScript + Flash Object<br />Server Side: Ruby<br /><br /><span style="FONT-WEIGHT: bold">3. How will it change the web?</span><br /><br />Chat is nice but think of all the collaboration and real-time data services you know, think of it functioning 10x faster.<br /><br /><span style="FONT-WEIGHT: bold">4. How can I start?</span><br /><br />Luckily, Juggernaut code is updated very frequently - improvements are made and bugs are being treated.<br /><br />Unfortunately, it changed it's already somewhat known API and so the already written tutorials are obsolete.<br /><br />Luckily, I am going to explain how to get this sweety to work in my next post:</p><p><a href="http://www.dorkalev.com/2008/04/juggernaut-up-to-date-tutorial-1042008.html">http://www.dorkalev.com/2008/04/juggernaut-up-to-date-tutorial-1042008.html</a><br /><br />Kudos to Alex MacCaw from <a href="http://www.eribium.org/">http://www.eribium.org/</a> for creating and maintaining Juggernaut</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-9182027507540537309?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-13816635339635220452008-01-30T19:35:00.000+02:002008-02-01T01:11:58.677+02:00"How to Start a Project" or "Chaotic Project Management, part 2"How to start a project?<br /><br />Get a reference point.<br />Whatever it is.<br /><br />Good chances are that the project is based on an emotional desire. No one wrote a <a href="http://www.google.com/search?hl=en&safe=off&q=define%3A+specification&btnG=Search">Specification</a>. Some one knows one part of the project, some one else knows another. There's no one 'oracle', no one place which holds the whole information in an ordinated manner. No constant reference point which one can work by, sometimes no one to ask either.<br /><span style="FONT-WEIGHT: bold"></span><br /><span style="FONT-WEIGHT: bold"></span>A few years ago I lived in the country side. One night I went out for a run in the fields. The hour was 22:00 and the fields were much vast and dark than I imagined them to be.<br /><br />Instead of 20 minutes run, I found myself unable to position, running around in circles (probably, I saw nothing). After a while, when I started loosing patience, I decided to stop choosing different directions every time I believe I run in the wrong direction and instead to find a light source and run towards it. 10 minutes later I found my self near the lights of a small village street far from my home. I continued walking down the street and from there hitch hiked home. The whole adventure took something like 90 minutes.<br /><br />When you get a project, look for reference points.<br /><br />Start building a <span style="FONT-WEIGHT: bold">model</span> with what you have. A model shouldn't be a specification document but the actual thing (if it's a program, you should actually program it).<br /><br />Always try to understand the small details, they will hold the keys to understanding the whole system but never try to implement all of them in the model.<br /><br />Cling to the big reference points.<br /><br /><ul><li>What are the main objects of the project?</li><li>What can't the project work without?</li></ul>Build it up together.<br />Don't try to cover 100% of the cases.<br />Build the simplest implementation.<br /><br /><span style="FONT-WEIGHT: bold">Remember, it is cheaper to build 2 tools which do specific functioning than building 1 which does both. It's much pricy to build or buy a Swiss Knife than a simple set of tools for each function needed.</span><br /><br />In databases, many times - it's chipper to do 2 SQL queries with a UNION instead of 1 complex one.<br /><br />Never try to fulfill all the functionalities of the project with one tool. It's cool and interesting but it might cost you your seat. If two functionalities are ment to be processed by one tool, it will naturally happen in a later phase - when similarities of the two different tools will intrigue you to commit this change specifically.<br /><br />As you continue in the process of building this model, you will naturally see what's central and what's not. It will be possible for you and for your client to ask the right questions and get the proper answers.<br /><br />Along the way, keep an open eye on the weak points of the model - write them down, think about them, plan and finally <a href="http://www.google.com/search?q=define%3A%20refactor&sourceid=mozilla2&ie=utf-8&oe=utf-8">refactor</a>.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-1381663533963522045?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com3tag:blogger.com,1999:blog-8158059990740821609.post-46045453943097830002008-01-18T21:32:00.000+02:002008-01-20T01:20:45.903+02:00Chaotic Project Management, part 1I always thought that writing a good spec before programming is mandatory.<br /><br />I like short but frequent discussions where a project spec is being written. I found out that having a spec (Agile, or not) is something mandatory. Ever since I understood I have to demand a spec from the customer, even if I have to sit down with him and write it together (frequently), programming became a much faster and easier task to commit.<br /><br />It is funny that in our world of 'thinking' people, so many times we don't think and rush to program without a true moment of thinking.<br /><br /><span style="font-weight: bold;">If you know the road, you can reach the target.</span><br /><br />If you start programming before having a plan, you might find yourself in a chaotic situation. You spent a lot of time programming stuff that isn't needed at all and now you have 20 waiting tasks with unknown priorities. Chaos. The customer isn't nice anymore, you are frustrated and the project becomes more and more complicated.<br /><br />In cases where the possibility of getting a good spec is low there's a project management style that has to be considered - the chaotic one.<br /><br /><span style="font-weight: bold;">The Chaotic Project Management</span><br /><blockquote><table align="center" border="0" cellpadding="0" cellspacing="2" width="601"><tbody><tr><td align="right" valign="top" width="5%"><i><a name="1">1</a></i> </td><td valign="top" width="95%"> In the beginning God created the heaven and the earth.<br /></td></tr> <tr><td align="right" valign="top" width="5%"><i><a name="2">2</a></i> </td><td valign="top" width="95%"> And the earth was without form, and void; and darkness <i>was</i> upon the face of the deep. And the Spirit of God moved upon the face of the waters.<br /><br /><div style="text-align: left;">Genesis I, 1-2<br /></div></td></tr></tbody></table></blockquote>Bring the customer to your office for a couple of days or go sit with him in his. Define short tasks together and to them with his constant observation. The customer should understand that for this matter you function as his 'hands' and to the actual programming but what will be is what he asks.<br /><br />Don't think about performance or beauty of code. Don't think about good DB structure, think about getting it done.<br /><br />This project management style gets results very fast but it is pricey and demands great patience. It should only be used when you know you can't go a step forward in the project because of lousy communication and bad specs.<br /><br />It should be done only with customers you have intimate relation with and are ready to go into this adventure with the price it demands.<br /><br />Many clients don't understand what project they wish to have. This project management style is all about getting to know the project. It's about managing something that has yet been formed ("without form and void").<br /><br />After a while, you'll have a clearer picture of what the project is and so would your customer.<br /><br />Now will be a good time for both of you to write a good spec and manage this project in a more conservative way.<br /><br /><a href="http://www.bartleby.com/108/01/1.html#S1">http://www.bartleby.com/108/01/1.html#S1</a><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-4604545394309783000?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com2tag:blogger.com,1999:blog-8158059990740821609.post-14456045850415439172008-01-05T21:54:00.000+02:002008-01-06T23:31:28.702+02:00How to form a team, part 1Since I started attending seminars with the great Italian coach <a href="http://youtube.com/watch?v=6nQ2Ba_UxSM">Patrizio Paoletti</a>, I have been trying to discover the keys that stand behind success stories. Whether it's a small change of habit, <a href="http://youtube.com/watch?v=_xcZTtlGweQ">the way of a poor man to richness</a> or <a href="http://www.youtube.com/watch?v=tSQSgwDRT84">helping mankind</a>.<br /><br />Last week I came across such an idea which I sense has more to, than what I understand and will present here.<br /><br />When you start a project you either do everything by yourself or you take all the decisions by yourself. Either way, all responsibility is yours and all the success and failure too.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R3_r7HygaCI/AAAAAAAAAAs/loTWZKXFjLU/s1600-h/Picture+5.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_4IC8U7ueZEs/R3_r7HygaCI/AAAAAAAAAAs/loTWZKXFjLU/s400/Picture+5.png" alt="" id="BLOGGER_PHOTO_ID_5152095899670833186" border="0" /></a>(during this post, you are BO)<br /><br />After a while, you gather up a team with different skills:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_4IC8U7ueZEs/R3_sk3ygaEI/AAAAAAAAAA8/ihNWBVNEyB0/s1600-h/Picture+3.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_4IC8U7ueZEs/R3_sk3ygaEI/AAAAAAAAAA8/ihNWBVNEyB0/s400/Picture+3.png" alt="" id="BLOGGER_PHOTO_ID_5152096616930371650" border="0" /></a>This time, you are still the manager of the project but you are also a programmer. You now have more responsibilities under the high responsiblity of "Fulfill the project's goals":<br /><ol><li>Make the team co-op toward success.<br /></li><li>Responsibility for Claudia's quality of work.<br />Claudia is a less experienced programmer than you and thus you have the responsibility for her current work and for her growth and evolution as a programmer.</li></ol>After a while, you hire more:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_4IC8U7ueZEs/R3_uaHygaFI/AAAAAAAAABE/CXB8uY1SPV0/s1600-h/Picture+2.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_4IC8U7ueZEs/R3_uaHygaFI/AAAAAAAAABE/CXB8uY1SPV0/s400/Picture+2.png" alt="" id="BLOGGER_PHOTO_ID_5152098631270033490" border="0" /></a><br />You no longer program but you are still managing.<br /><br />Derek, Cindy and Joe are the most experienced experts in their fields and thus each of them has the cross-responsibility for his field. Tom for design, Derek for QA and Joe for programming. They are <span style="font-weight: bold;">Field Managers</span>.<br /><br />Paris and Dave are project managers you hired and have the responsibility for each project's success. They are <span style="font-weight: bold;">Project Managers</span>.<br /><br />You, however, have the higher responsibility for Paris and Dave success in their duty and their improvement.<br /><br /><span style="font-weight: bold;">What is the third dimension of this Matrix?</span> Will.<br /><br />Each person in this matrix has a skill that for which he was hired: Programmer, Designer, QA or Manager. Each person in this matrix has a level of management skills, hopefully the better managers actually get to hold this title as Project Managers or Field Managers.<br /><br />The third point that each person in this matrix relies-on is his will. Motivation, higher goal or quest - the reason for which I do what I do. Whether it is in order to feed my family or to fulfill my curiosity of the profession, I must be motivated. <span style="font-weight: bold;">Yes!!!<br /></span><br />Kudos to Koby Menachemi for this insight<br /><br /><br />...and now to something completely different... Jovanotti -<br /><br /><div style="text-align: center;"><br /><object height="355" width="425"><param name="movie" value="http://www.youtube.com/v/sCe0tuqPKiU&rel=1"><param name="wmode" value="transparent"><embed src="http://www.youtube.com/v/sCe0tuqPKiU&rel=1" type="application/x-shockwave-flash" wmode="transparent" height="355" width="425"></embed></object><br /><br /></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-1445604585041543917?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com2tag:blogger.com,1999:blog-8158059990740821609.post-52838332085589633972008-01-04T02:17:00.000+02:002008-01-04T02:57:55.664+02:00Standards VS. PerformanceToday I had to create an XML with ~ 7000 records.<br /><br />The first role looked like this:<br /><br /><code><br /><u>Controller</u><br />def all_articles<br /> @articles = Article.find_all<br /> render :layout => false<br />end<br /><br /><u>View - articles.rxml</u><br />xml.instruct! :xml, :version => '1.0'<br />xml.root do<br /> xml.articles do<br /> @articles.each do |article|<br /> xml.article do<br /> xml.id article.id<br /> xml.title article.title<br /> end<br /> end<br /> end<br />end<br /></code><br /><br />The size of the XML was ~ 800kb and it took 7 seconds to render.<br />Horror, ah?<br /><br />The truth is, after thinking, I don't really need an XML in this specific case. All the data is going to be read by a JavaScript that I can modify to get any format I like.<br /><br />The solution:<br /><br /><code><br /><u>Controller</u><br />def all_articles<br /> ActiveRecord::Base.connection.execute("SET SESSION group_concat_max_len = 999999999;")<br /> @articles_big_csv = ActiveRecord::Base.connection.execute("select group_concat(articles.id,'>',articles.name SEPARATOR '<') from articles").fetch_row.first render :layout => false<br />end<br /><br /><u>View - aricles.rxml</u><br />xml.instruct! :xml, :version => '1.0'<br />xml.root do<br /> xml.articles @articles_big_csv<br />end<br /></code><br /><br />The output of "select group_concat(articles.id,'>',articles.name SEPARATOR '<') from articles" is in the format of "ARTICLE ID>ARTICLE TITLE<next article="" id="">NEXT ARTICLE TITLE..."<br />(I can use the "<>" as separators since I dont allow them in an article name; else I could use any sepeartors I like)<br /><br />Later, on the parsing JavaScript side I will split the string by '<' to get the rows and each row I will split by '>' to get it's columns.<br /><br /><strong>The size of this output is now 200kb and rails can render it 11(req/s)</strong><br /><br />(...if you are lucky and your server gzips everything it goes down to 80kb)<br /><br /><strong>What did we do?</strong><br />1. Smallest size: we didn't use XML standards but a simple primitive string with separators.<br />2. Fastest tool: we did all the work in MySql which is much faster than Ruby.<br /><br /><br /><br />Kudos to Roman Krom for the 'let sql do the work for you' philosophy<br />Kudos to Boris Peterbard for teaching me the <a href="http://db4free.blogspot.com/2006/01/hail-to-groupconcat.html">group_concat</a> magic<br /><br /></next><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-5283833208558963397?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com2tag:blogger.com,1999:blog-8158059990740821609.post-61000404051067453662008-01-04T01:23:00.000+02:002008-01-04T02:12:09.467+02:00Not RunningIt's been a week since the last time I ran.<br /><br />Last friday, December 28 2007, I woke up at 6:00am and went for a casual morning run with Arik, a dear friend from work. I already felt a bit dizzy and it was very cold but we ran anyway, a bit slow and with a Fleece I ran for 41 minutes at 156 average heart rate.<br /><br />When I got back home I cleaned the house and by 1:15pm I fall to bed and slept until 4:30pm.<br /><br />Saturday already felt worst and Sunday I was already sick.<br /><br />It's been a week since the last time I ran.<br /><br />I spent more time in bed and in-front of T.V. this week than any time before in the last 2-3 month.<br /><br />Except for feeling bad and weak this week, the other expensive "price" I paid this week was of mental slowness. I already watched it before that when I run my mind is in "better shape" and that I can think much clearer but this week it really hit me.<br /><br />At the end of each day I try to focus and in my head scan over the day that passed, this week it was very hard. Every-time I tried to recall the day that passed, everything was far and faded.<br /><br />Today I already felt better and got back to regular work day in the office. I was restless and kept chewing things throughout the day. My mouth needed something to play with.<br /><br />Weeks like this one are the reason I always return to running. It clears my mind, cools my heart and relax my body. After running I can think clearer, I am much more calm and I am not as irritated and annoyed as usual.<br /><br />Next Thursday I will run 10 km at <a href="http://www.tiberias-marathon.co.il/en/index.php">Tiberias Marathon</a>.<br /><br />* If you are a hebrew reader, pay a visit to <a href="http://shvoong.co.il/or/indext.asp">Or's blog</a><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-6100040405106745366?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-24421406332383685712007-12-31T23:55:00.000+02:002008-01-01T00:34:38.913+02:00Refactoring: We are not alone!<span style="font-size:130%;"><a href="http://refactormycode.com/">http://refactormycode.com</a></span><br />Read this blog, it will make you smile!<br /><br />I did some testing on the refactorings suggested in:<br /><a href="http://refactormycode.com/codes/2-ruby-simple-loop">http://refactormycode.com/codes/2-ruby-simple-loop</a><br /><br />testing.rb<br /><code><br />def prof(t = 1, output = :puts)<br /> starting_time = Time.now<br /> t.times { yield }<br /> dlta = (Time.now - starting_time).to_f/t<br /> case output<br /> when :ret<br /> "### time: #{dlta.to_s}(s) . req/s: #{(1/dlta)}"<br /> else<br /> puts "### time: #{dlta.to_s}(s) . req/s: #{(1/dlta)}"<br /> end<br />end<br /><br />times = []<br />times << ["(1..10).each do |i|<br /> puts i<br />end",<br />prof(1000,:ret) {<br /> (1..10).each do |i|<br /> puts i<br /> end<br />}]<br /><br />times << ["for i in (1..10)<br /> puts i<br />end<br />",prof(1000,:ret){<br /> for i in (1..10)<br /> puts i<br /> end<br />}]<br /><br />times << ["(1..10).each { |i| puts i }",prof(1000,:ret){<br /> (1..10).each { |i| puts i }<br />}]<br /><br />#times << ["puts (1..10).to_a * '\n'",prof(1000,:ret){<br /># puts (1..10).to_a * "\n"<br />#}]<br /><br />#times << ["puts (1..10).to_a",prof(1000,:ret){<br /># puts (1..10).to_a<br />#}]<br /><br />times << ["1.upto(10) { |i| puts i }",prof(1000,:ret){<br /> 1.upto(10) { |i| puts i }<br />}]<br /><br />times << ["puts 1,2,3,4,5,6,7,8,9,10",prof(1000,:ret){<br /> puts 1,2,3,4,5,6,7,8,9,10<br />}]<br /><br />times << ["10.times {|i| p i+1}",prof(1000,:ret){<br /> 10.times {|i| p i+1}<br />}]<br /><br />puts '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'<br />times.collect { |t|<br /> puts t<br /> puts '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'<br />}<br /> </code><br /><span style="font-style: italic;">Two of the suggestions:</span><br /><ul style="font-style: italic;"><li>puts (1..10).to_a<br /></li><li>puts (1..10).to_a * "\n"</li></ul><span style="font-style: italic;">don't really work, so I left them out of the tests)</span><br /><br />And the results are ...<br /><code><br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *<br />(1..10).each do |i|<br />puts i<br />end<br />### time: 0.000165467(s) . req/s: 6043.50112106946<br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *<br />for i in (1..10)<br />puts i<br />end<br />### time: 0.00018765(s) . req/s: 5329.07007727152<br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *<br />(1..10).each { |i| puts i }<br />### time: 0.00020241(s) . req/s: 4940.46736821303<br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *<br />1.upto(10) { |i| puts i }<br />### time: 0.000216612(s) . req/s: 4616.54940631175<br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *<br />puts 1,2,3,4,5,6,7,8,9,10<br />### time: 0.000164026(s) . req/s: 6096.59444234451<br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *<br />10.times {|i| p i+1}<br />### time: 0.000208756(s) . req/s: 4790.28147693958<br />* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *</code><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-2442140633238368571?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com5tag:blogger.com,1999:blog-8158059990740821609.post-63477603800627823002007-12-30T21:48:00.000+02:002007-12-31T08:45:15.868+02:00Why I love Ruby on Rails and what should be said on it's performance , part 1<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://rubyonrails.com/images/rails.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 97px; height: 124px;" src="http://rubyonrails.com/images/rails.png" alt="" border="0" /></a><br />In less than a week, you can establish a working model for your final product.<br /><p>It is, however, very unwise to consider this is the end of the process.</p><p>Ruby on Rails allows ultra-fast development but all this comes in exchange to performance and efficiency.<br /></p><p>At the end of the first development period you find yourself with a great working copy but with very low efficiency and as soon as your site starts growing you have to add more servers, more memory, more everything.<br /></p><p>What can and should be done in this stage is the infamous 're-factoring' procedure with high attention on performance.<br /></p><p>For example for Article and User where each user has many articles and each article<br />belongs to a user ( 1 -to- many relationship)<br /></p><p>If we want to get an article's user email we railslishly write:</p><code>Article.find(123).user.email<br /></code><br />Which feeds our logs with:<br /><code><br />Article Load (0.002447) SELECT * FROM articles WHERE (articles.`id` = 123)<br />User Load (0.002856) SELECT * FROM users WHERE (users.`id` = 8)</code><br /><p>This isn't a problem if you have a small application, this isn't a lot ah? 2 are 100% more SQL queries than only 1 query...<br /><br />Actually, it's okay to live with it as long as you don't need to grow. When you do, you have to learn SQL.<br /></p>The truth is even basic SQL can save you here (something PHP or ASP developers would never brag about...):<br /><code><br />select * from articles inner join users on users.id = articles.user_id where articles.id = 123<br /></code><br />Word is around that Ruby on Rails is slow because of Ruby. The truth for large scale websites is that Rails has much more to do with performance than Ruby.<br /><br />Let's try a <a href="http://www.dorkalev.com/2007/12/tiny-profiling-utility.html">Tiny Profiling Utility</a> on the the scenario described above, where in both cases I want to get an author email according according to it's ID:<br /><code><br />>> prof(1000) { Article.find_by_sql('select * from articles inner join users on users.id = articles.user_id where articles.id = 123').first['email'] }<br />time: 0.004523629(s) . req/s: 221.061453094407<br />=> nil<br />>> prof(1000) { Article.find(123).user.email }<br />time: 0.005518112(s) . req/s: 181.221403262565<br />=> nil<br />>><br /></code><br />For one simple action we see a difference of around 20% in speed. Take into consideration that more time consumed by the SQL server is more time other queries are waiting in line, etc. etc.<br />Let's do the previous test for two articles (123 and 567):<br /><code><br />>> prof(1000) {<br />a = Article.find_by_sql('select * from articles inner join users on users.id = articles.user_id where articles.id = 567 or articles.id = 123')<br />a[0]['email'] + a[1]['email']<br />}<br />time: 0.004959934(s) . req/s: 201.615586013846<br />=> nil<br />>> prof(1000) {<br />a = Article.find(567,123)<br />a[0].user.email + a[1].user.email<br />}<br />time: 0.008703669(s) . req/s: 114.894075130844=> nil<br /></code><br />Now that's around 40% difference... imagine what would happen in the case of Many-to-Many connection...<br /><br />The truth is that eager loading in Rails, should solver this issue - but for some reason it's slower... :<br /><code>>> prof(1000) {<br /> a = Article.find(567,123, :include => :user)<br /> a[0].user.email+a[1].user.email<br /> }<br />time: 0.006641206(s) . req/s: 150.575061216291<br />=> nil<br /></code><br />Rails is a great framework and Ruby is a wonderful language, use them and learn some SQL too, they work much faster together...Start using it now: <a href="http://rubyonrails.com/">http://rubyonrails.com</a><br /><p>Don't forget your sql... <a href="http://w3schools.com/sql/default.asp">http://w3schools.com/sql/default.asp</a><br /></p><p>enjoy!</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-6347760380062782300?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-56743431249165593612007-12-28T08:40:00.000+02:002007-12-30T23:28:54.514+02:00Mongrel: A recipe for Success, part 1Take two different good things and combine them together.<br /><br />Examples:<span style="font-weight: bold;"><br /><br /></span><span style="font-size:100%;"><a style="font-weight: bold;" href="http://wii.com/">Wii</a> - Ninetendo's winning game console</span><span style="font-weight: normal;"><br /><br />Nintendo took two simple technologies:</span><ol><li><span style="font-weight: normal;">The Wiimote (<a href="http://www.x-arcade.com/newsletter/Wii%20Dupe.shtml">http://www.x-arcade.com/newsletter/Wii%20Dupe.shtml</a>)<br /><blockquote>The second technology that brings it all together is the use of motion sensors. This could be accomplished with the use of Gyros, as <a href="http://www.gamecubicle.com/news-nintendo_gyration.htm" target="_blank" class="inline">Nintendo did buy a sizable amount of shares</a> in the company <a href="http://www.gyration.com/en-us/HomeOfficePC.html" target="_blank" class="inline">Gyration, Inc</a> back in September of 2001. But we do know it does use <a href="http://www.analog.com/en/prod/0,2877,764%255F800%255FADXL330,00.html" target="_blank" class="inline">iMEMS®</a> solid state <a href="http://en.wikipedia.org/wiki/Accelerometer" target="_blank" class="inline">accelerometers</a> that detect motion by way of acceleration which were provided by <a href="http://www.analog.com/en/press/0,2890,3__99573,00.html" target="_blank" class="inline">Analog Devices, Inc.</a> and/or <a href="http://www.planetgamecube.com/newsArt.cfm?artid=11580" target="_blank" class="inline">STMicroelectronics</a>. After much prying around at E3, I was told (by Nintendo's Developer Support) that there are three accelerometers at work in the Wiimote. There are also at least two accelerometers used in the nunchuck add-on to detect motion in it as well.<br /></blockquote></span></li><li><span style="font-weight: normal;">The Machine (<a href="http://en.wikipedia.org/wiki/Wii">http://en.wikipedia.org/wiki/Wii</a>)<br /></span><blockquote><ul><span style="font-weight: normal;"><li><a href="http://en.wikipedia.org/wiki/Central_processing_unit" title="Central processing unit">CPU</a>: <a href="http://en.wikipedia.org/wiki/PowerPC" title="PowerPC">PowerPC</a>-based <a href="http://en.wikipedia.org/wiki/Broadway_%28microprocessor%29" title="Broadway (microprocessor)">"Broadway"</a> processor, made with a <a href="http://en.wikipedia.org/wiki/90_nanometer" title="90 nanometer">90 nm</a> <a href="http://en.wikipedia.org/wiki/Silicon_on_insulator" title="Silicon on insulator">SOI</a> <a href="http://en.wikipedia.org/wiki/CMOS" title="CMOS">CMOS</a> process, reportedly<sup>†</sup> clocked at 729 <a href="http://en.wikipedia.org/wiki/Hertz" title="Hertz">MHz</a><sup id="_ref-IGNTech_0" class="reference"><a href="http://en.wikipedia.org/wiki/Wii#_note-IGNTech" title="">[47]</a></sup></li></span></ul></blockquote></li></ol>Instead of reinventing the wheel (<a href="http://en.wikipedia.org/wiki/PlayStation_3_hardware">http://en.wikipedia.org/wiki/PlayStation_3_hardware</a>) they took two good technologies and mashed them up. <span style="text-decoration: underline;"><br /><br /></span><a href="http://www.msnbc.msn.com/id/16115967/">http://www.msnbc.msn.com/id/16115967/</a><br /><br /><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/MFoyp71xw3w&rel=1"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/MFoyp71xw3w&rel=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-5674343124916559361?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-76465004901674055122007-12-28T00:33:00.000+02:002007-12-30T23:29:46.571+02:00Ruby 1.9.0Have you heard it was released?<br /><br />http://www.ruby-lang.org/en/news/2007/12/25/ruby-1-9-0-released/<br /><br />howto install:<br /><code><br />autoconf<br />./configure --prefix=/usr/local/ruby1.9<br />make<br />sudo make install<br /><br /></code><br /><br />For a long while we were expecting this product that should increase Ruby performance tremendously.<br />Mind you, I had yet seen a web application running slow because of Ruby. Most of the cases it was misusage of database and memory structures, the major down-pit Rails developers fall into (newbies as well as experts).<br /><br />Ruby 1.9 is here anyway (dev. version), let's give it a try!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-7646500490167405512?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-26901376174918348692007-12-27T23:44:00.000+02:002007-12-30T23:30:57.341+02:00Tiny profiling utility<code><br />def prof(t = 1)<br /> starting_time = Time.now<br /> t.times { yield }<br /> dlta = (Time.now - starting_time).to_f<br /> puts "time: #{dlta.to_s}(s) . req/s: #{(1/dlta)}"<br />end<br /></code><br /><ul><li>Use prof to <span style="font-weight: bold;">measure</span> how long a function or any block of code takes.</li><li>Use parameter <span style="font-weight: bold;">t</span>>1 to run the block code <span style="font-weight: bold;">t</span> times and return the average time per test<br /></li></ul>Examples:<br /><code><br />>> prof { Flight.find_first }<br />time: 0.002032(s) . req/s: 492.125984251969<br />=> nil<br />>> prof { Flight.find_first }<br />time: 0.00201(s) . req/s: 497.512437810945<br />=> nil<br />>> prof(10) { Flight.find_first }<br />time: 0.001351(s) . req/s: 740.19245003701<br />=> nil<br />>> prof(100) { Flight.find_first }<br />time: 0.0012727(s) . req/s: 785.731122809775<br />=> nil<br />>> prof(1000) { Flight.find_first }<br />time: 0.001415021(s) . req/s: 706.703292742652<br />=> nil<br />>> prof(10000) { Flight.find_first }<br />time: 0.0013922995(s) . req/s: 718.236270285237<br />=> nil<br />>><br /></code><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-2690137617491834869?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-42492634631791727992007-12-27T01:55:00.000+02:002007-12-30T23:31:21.182+02:00ActiveRecord::Base#exists?<code>class ActiveRecord::Base<br /> def self.exists?(conditions, unique_id = nil)<br /> count1(conditions, unique_id)>0<br /> end<br />end<br /></code><br />Returns true/false if at least one row that follows ceratin <span style="font-weight: bold;">conditions</span> is found<br /><ul><li>Can only be used along with <a href="http://www.dorkalev.com/2007/12/class-activerecordbase-def-self.html"><span style="text-decoration: underline;">count1</span></a></li><li><span style="font-weight: bold;">unique_id</span> - used when you still want to allow a certain raw (defined by id...) to be left out of the count. Useful for validations, ie:<br /><code><br />User.exists? ['nick != ?',user.nick], user.id<br /></code><br /></li><br /></ul><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-4249263463179172799?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0tag:blogger.com,1999:blog-8158059990740821609.post-41447608678828775652007-12-27T01:43:00.000+02:002008-02-01T01:04:50.013+02:00ActiveRecord::Base#count1 - fastest counter ever<code><br />class ActiveRecord::Base<br /> def self.count1(conditions, unique_id = nil)<br /> connection.execute("select count(1) from #{table_name} where #{sanitize_sql(conditions)} #{'and id<>'+unique_id.to_s if unique_id}").fetch_row.first.to_i<br /> end<br />end</code><br /><ul><li><span style="FONT-WEIGHT: bold">count(1)</span> is the fastest way, as far as I know, for mysql to count table elements.<br />Why should we use the relatively expensive count(*) when we can use this modest counter?<br /></li><li><span style="FONT-WEIGHT: bold">conditions </span>- can come as ['title = ?','canon'] which than sanitized by <span style="FONT-WEIGHT: bold">sanitize_sql </span>to 'title = "canon"', for example.<br /></li><li>All this code can be put in <span style="FONT-WEIGHT: bold">environment.rb</span> and than it extends your <span style="FONT-WEIGHT: bold">ActiveRecord::Base</span> objects, thus it will exetend any Model in your railsish system.</li><li style="FONT-WEIGHT: bold">unique_id - used when you still want to allow a certain raw (defined by id...) to be left out of the count. Useful for validations, ie:<br /><code><br />User.count1(['nick != ?',user.nick], user.id)>0<br /></code></li></ul><br />Everything here applies to Mysql 5.0.14<br />(never tested on anything else...)<br /><br />Kudos to Boris Peterbarg<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8158059990740821609-4144760867882877565?l=www.dorkalev.com'/></div>dor kalevhttp://www.blogger.com/profile/18055521336329098014noreply@blogger.com0