<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" ><channel><title>/dev/maverick &#187; Uncategorized</title> <atom:link href="http://ilyasterin.com/blog/category/uncategorized/feed" rel="self" type="application/rss+xml" /><link>http://ilyasterin.com</link> <description>Against the grain software and startups</description> <lastBuildDate>Tue, 29 Nov 2011 20:17:14 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Our experience with distributed computing using Gridgain</title><link>http://ilyasterin.com/blog/2011/11/our-experience-with-distributed-computing-using-gridgain.html</link> <comments>http://ilyasterin.com/blog/2011/11/our-experience-with-distributed-computing-using-gridgain.html#comments</comments> <pubDate>Tue, 29 Nov 2011 18:49:47 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[distributed computing]]></category> <category><![CDATA[gridgain]]></category> <category><![CDATA[Java]]></category> <category><![CDATA[scala]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=405</guid> <description><![CDATA[Intro I&#8217;ve been doing distributed computing in various forms for many years. Some at the higher level, some at the lower level and can tell you that with all the research advances and toolkits out there, it&#8217;s getting easier, but it&#8217;s still not as straight forward as it should be. Similar issues exist in multi-[process&#124;thread] [...]]]></description> <content:encoded><![CDATA[<h3>Intro</h3><p>I&#8217;ve been doing distributed computing in various forms for many years.  Some at the higher level, some at the lower level and can tell you that with all the research advances and toolkits out there, it&#8217;s getting easier, but it&#8217;s still not as straight forward as it should be.  Similar issues exist in multi-[process|thread] implementations.  Although abstraction toolkits exist and they definitely make it easier to perform such actions without knowing  much about implementing distributed algorithms, they are still leaky abstractions that in most non-trivial cases lead to having to have knowledge of the memory model, synchronization semantics, mutability, network topologies, etc&#8230;  I&#8217;m not saying this is bad, I&#8217;m just saying that we haven&#8217;t yet reached the point where distributed or multi-[process|thread] computing is a cross cutting application concern.  We have to actively bake it into our applications.  I&#8217;m not arguing that abstractions should make developers ignorant of the underlying mechanisms, it&#8217;s just that they should be introduced at different levels of abstraction.  It&#8217;s good to know what makes things tick (i.e. algorithms, data structures, etc&#8230;).  Just look at the ORM world.  The promise of not having to know SQL and just programming using OO took the OO world by storm.  The naive thought that if you didn&#8217;t know the latest/greatest in ORM, you weren&#8217;t worthy.  Years later, it turned out to be just a fad.  Most have now turned back to SQL or some abstraction that&#8217;s flexible enough to allow you to work as low level or as high level as needed.  In some cases, people are turning away from SQL data stores completely, but that&#8217;s another story.</p><h3>A Little History</h3><p>About 3 years ago, I was in the process of starting a company with my partners and we had a dilemma.  We needed to process large amounts of data in near real-time.  We also needed to be able to scale this horizontally in a &#8220;near&#8221; linear fashion.  Data throughput was not temporally predictable, if predictable at all.  After doing some searching and trying to fight the urge to implement things from scratch, we came upon the <a href="http://en.wikipedia.org/wiki/Tuple_space">tuple-space programming model</a>.  It&#8217;s similar to the <a href="http://en.wikipedia.org/wiki/Blackboard_system">blackboard system</a> for those that have an AI background.  This is exactly what we needed, some shared distributed memory model that we didn&#8217;t have to think about (it presented itself as a single unified tuple space), and a programming API that allowed us to distribute jobs to work on the data stored in that model. <a href="http://en.wikipedia.org/wiki/JavaSpaces#JavaSpaces">Javaspaces</a> is the java specification for <a href="http://en.wikipedia.org/wiki/Tuple_space">Tuple Space Model</a>.  At the time, the only company that implemented this spec was GigaSpaces.  We took their toolkit for a spin and it worked.  The model was pleasant to program to and things were great.  That&#8217;s until they didn&#8217;t work.  Debugging was difficult, it leaked distributed abstraction.  Deployment was also not very straightforward.  None of that was the limitation of the Tuple Space Model, rather it was the implementation.  I&#8217;m not saying GigaSpaces didn&#8217;t have a good implementation.  I actually think it was rather nice at the time and am sure it&#8217;s way better now.  At one point, we wrote an intermediary home-brewed rewrite of the system, so that we didn&#8217;t have to rush with the main implementation and can flush it out without harsh time constraints.  In a few months, we ended up folding the plans to use GigaSpaces not because of the software, but rather because the company [GigaSpaces] had financial difficulties and their software, not being open source, was in flux in our opinion and we didn&#8217;t want to bet the success of our company on a commercial product of a company that looked like they were going to fold.  Years later, they are still in business, great for them, but I don&#8217;t particularly regret our decision, especially looking at today&#8217;s landscape.</p><p>Most of our backend software is written in Java, Scala, and Python.  Our web CRUD front end is written in PHP.  The front end has a model that reflects our business domain, though it already encapsulates all of the business rules for our relational backend data store.  We have a calculation process that utilizes these business rules to perform a bunch of operations and in the process reads/writes to the database.  This process is very involved as it crunches hundreds of thousands of data points and will go up to  millions in the next few months.  It was written in PHP.  We want to rewrite it using the model of distributing the data and computation using data affinity <em>(collocating data and computations together)</em>.  We&#8217;ve done it before and it works.  So we&#8217;re happy to do it again, but we want to do this right and that might take some time.  In the meantime, we wanted to take an intermediary step of distributing the workload amongst multiple servers (brought up and down as needed).  I&#8217;ve been looking at numerous distributed toolkits for a while, from Hadoop to Akka to Gridgain.  One that always stood out in the crowd has been Gridgain and in the last 6 months I&#8217;ve tried to find some place where it would pay its dividends.  This project was it.  We had a distributed scheduling service running on ec2 within <strong>a week</strong>, not bad, being that I had to learn the APIs and various ec2 deployment ins and outs.</p><h3>Implementation</h3><p>Our implementation has a scheduler that decides what computations need to be performed.  We then schedule these computations by pushing a job to a distributed worker node.  Because our job is run as a shell script (invoking PHP) and outputs statistics after it successfully runs, we run the job using java&#8217;s <em>ProcessBuilder</em> class.  We then run the process, and capture its output (in json).  The output is then returned to the scheduling node, evaluated, and logged.  The scheduler then knows that this job can run again (we have a need to ensure the job is a singleton when it comes to running in a grid).</p><p>Our implementation is in Scala.  Gridgain has a rather nice Scala DSL.  We used it as much as we could, but in some cases resorted to java API for reasons I&#8217;ll explain later.</p><p>First, here is our simple task that scheduler (once it figures out a job needs to run), pushes to remote nodes&#8230;</p><div id="gist-1405719" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'>import org.gridgain.grid.GridClosureCallMode._</div><div class='line' id='LC2'>import org.gridgain.scalar.scalar</div><div class='line' id='LC3'>import scalar._</div><div class='line' id='LC4'>import java.io.File</div><div class='line' id='LC5'>import io.Source</div><div class='line' id='LC6'>import net.liftweb.json._</div><div class='line' id='LC7'>import net.liftweb.json.JsonDSL._</div><div class='line' id='LC8'>import java.util.{Date, Collections}</div><div class='line' id='LC9'>import java.util.concurrent.{Callable, TimeUnit, Executors, ConcurrentHashMap}</div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><br/></div><div class='line' id='LC12'>class GridTask(scriptCommand:String, scriptEnv:String, scriptDir:String) extends Callable[JValue] {</div><div class='line' id='LC13'><br/></div><div class='line' id='LC14'>&nbsp;&nbsp;def call() = {</div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;val proc = new ProcessBuilder(scriptCommand.split(&quot; &quot;): _*)</div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;proc.command()</div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;proc.directory(new File(scriptDir))</div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;proc.environment().put(&quot;APPLICATION_ENV&quot;, scriptEnv);</div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;val p = proc.start()</div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;p.waitFor();</div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;val retString = Source.fromInputStream(p.getInputStream).getLines()</div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;val errString = Source.fromInputStream(p.getErrorStream).getLines()</div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;if (p.exitValue == 0 &amp;&amp; !retString.isEmpty) {</div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parse(retString.mkString(&quot;\n&quot;))</div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;} else {</div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&quot;event_id&quot; -&gt; 53) ~</div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&quot;start_time&quot; -&gt; new Date().getTime) ~</div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&quot;error&quot; -&gt; errString)</div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;}</div><div class='line' id='LC30'>&nbsp;&nbsp;}</div><div class='line' id='LC31'>}</div><div class='line' id='LC32'><br/></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/1405719/f92c3a8ba847cb7816d1d876e0dc60c1ccf42811/gistfile1.txt" style="float:right;">view raw</a> <a href="https://gist.github.com/1405719#file_gistfile1.txt" style="float:right;margin-right:10px;color:#666">gistfile1.txt</a> <a href="https://gist.github.com/1405719">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>The above is pretty self explanatory.  I kept of bunch of irrelevant things around, like inferring the return of the process and parsing/returning json.</p><p>Our scheduler is more complex, so I won&#8217;t show it, but it&#8217;s all custom business logic, nothing that has to do with scheduling a job on the grid.  To scheduler the job, all you have to do is&#8230;</p><pre><code>val retVal = grid.remoteProjection().call(
      UNICAST, 
      new GridTask(scriptCommand, scriptEnv, scriptDir))
</code></pre><p><em>retVal</em> is now the <em>JValue</em> instance returned from the remote job.  If you get rid of the custom business logic in the <em>GridTask</em> implementation, the whole thing is a few lines of code.  Talk about an &#8220;abstraction&#8221;!  Also, one mention is that don&#8217;t let simplicity in their examples fool you.  Their API is full blown and gives you the level of granularity you need, jus ask, and ye shall have.  For example, <em>grid.remoteProjection()</em> returns a projection of all remote nodes (not including the current node, which is local).  This is important for us because we didn&#8217;t want the local node (scheduler) doing any computations as it&#8217;s running on a box not able to support it.</p><h3>Deployment</h3><p>One great thing about Gridgain, is that it works the same on a single node as it does on multiple nodes (same physical box), as it does on multiple physical nodes.  You can also start multiple nodes within a single JVM.  When I first heard this, I thought to myself, sounds great, but why?  Nikita mentioned debugging and then a light came on.  I remembered debugging GigaSpaces stuff and what worked on a single node, sometimes didn&#8217;t on multiple nodes.  Mind, it was almost always my mistake, but debugging it was not very easy.</p><p>Our infrastructure runs on EC2.  Gridgain provides EC2 images, but besides the fact that they run CentOS I believe, which I&#8217;ve grown to dislike, I&#8217;m also a control freak when it comes to my servers.  I want them clean and mean:-).  I prefer debian/ubuntu boxes, though I opted to create my own AMI.  Installing Gridgain was easy, configuring is also a 2 minute task.  It took me a few hours to figure it out and with the help of the forum, the configuration was a few lines of XML.  We&#8217;re using the community edition, which comes with rudimentary IP discovery SPI.  They have much more robust discovery SPIs available in their enterprise edition. One which I think makes the most sense on EC2 is S3 discovery.  Basically, it uses S3 to write node information, and all nodes communicate using a S3 bucket.  Makes sense.  We weren&#8217;t ready to dish any money out for enterprise version yet, so I had to settle for IP discovery.  In our case, it wasn&#8217;t hard.  Basically, the scheduler in a single node that runs behind an elastic IP address that never changes.  That means that the other boxes only have to know the IP address of the scheduler to make the initial communication.  Once it can connect to one node, it joins the full grid.  Because we have a single scheduler, if the scheduler goes down, the workers are no longer a part of the grid until the scheduler comes back up.  This is OK for us, since due to some domain details, we can only have a single scheduler at this time and we&#8217;re OK with that single point of failure, especially being that we can bring it back up in no time and the worker nodes patiently retry the join operation at an interval and then rejoin the grid once the scheduler is back up.  This is out topology.  Gridgain supports pretty much what ever you want, including P2P no single point of failure topology.  Below are the relevant configurations for our stuff&#8230;</p><p>Scheduler<div id="gist-1405802" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'>&lt;property name=&quot;discoverySpi&quot;&gt;</div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean class=&quot;org.gridgain.grid.spi.discovery.tcp.GridTcpDiscoverySpi&quot;&gt;</div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;localAddress&quot; value=&quot;10.1.1.1&quot;/&gt;</div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;ipFinder&quot;&gt;</div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean class=&quot;org.gridgain.grid.spi.discovery.tcp.ipfinder.vm.GridTcpDiscoveryVmIpFinder&quot;&gt;</div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;shared&quot; value=&quot;true&quot;/&gt;</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;addresses&quot;&gt;</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;</div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;10.1.1.1:47500&lt;/value&gt;</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;</div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;heartbeatFrequency&quot; value=&quot;2000&quot;/&gt;</div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;</div><div class='line' id='LC16'>&lt;/property&gt;</div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/1405802/a310eff1a1b0c4efda381d926cfa985aa85ba972/gistfile1.txt" style="float:right;">view raw</a> <a href="https://gist.github.com/1405802#file_gistfile1.txt" style="float:right;margin-right:10px;color:#666">gistfile1.txt</a> <a href="https://gist.github.com/1405802">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div></p><p>The 10.1.1.1 is the local IP address of the scheduler box.  The ip is repeated in the <em>&#8220;addresses&#8221;</em> section, telling gridgain that this can be the sole server and it doesn&#8217;t have to join a grid topology before it goes live.  Also, <em>shared=&#8221;true&#8221;</em> is important, as it tells gridgain to share configurations amongst the boxes in the grid.  Without it, you&#8217;ll have an &#8220;order of operations&#8221; issue, where a master must be started first before the worker.  With it, that issue is moot and you can start/stop things as you please.  I wish they would make this the default.</p><p>Right now, Gridgain cannot bind to a wildcard, though you have to specify the private IP address.  If it changes (box reboots), you have to change it too.  They promised a solution in their next release, which will allow to listen on private IP and communicate over public IP.  This will help in other NAT topologies.  Being able to listen to a wildcard will also help in having a config you never have to change.  But even with this caveat, this is quite a breeze.</p><p>The worker config is similar, except it only needs to know about the scheduler and does not need to operate until it has joined a topology&#8230;</p><div id="gist-1405840" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'>&lt;property name=&quot;discoverySpi&quot;&gt;</div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean class=&quot;org.gridgain.grid.spi.discovery.tcp.GridTcpDiscoverySpi&quot;&gt;</div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;localAddress&quot; value=&quot;10.1.1.2&quot;/&gt;</div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;ipFinder&quot;&gt;</div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;bean class=&quot;org.gridgain.grid.spi.discovery.tcp.ipfinder.vm.GridTcpDiscoveryVmIpFinder&quot;&gt;</div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;shared&quot; value=&quot;true&quot;/&gt;</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;addresses&quot;&gt;</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;list&gt;</div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;value&gt;scheduler.node.com:47500&lt;/value&gt;</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/list&gt;</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;</div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/property&gt;</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&quot;heartbeatFrequency&quot; value=&quot;2000&quot;/&gt;</div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&lt;/bean&gt;</div><div class='line' id='LC16'>&lt;/property&gt;</div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/1405840/6bc74516c80a968d23cc7ef820f520ea707aafbe/gistfile1.txt" style="float:right;">view raw</a> <a href="https://gist.github.com/1405840#file_gistfile1.txt" style="float:right;margin-right:10px;color:#666">gistfile1.txt</a> <a href="https://gist.github.com/1405840">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><h3>Caveats</h3><p>There are small caveats I found, none of which created much of a hurdle.</p><p>First is serialization.  In my case, I&#8217;m was using logback for logging, gridgain uses log4j.  We both use slf4j, which takes the first in the classpath.  If you&#8217;re going to distributed a job that references something that clashes with classpaths, you have to do some classpath mangling.  Removing log4j from gridgain&#8217;s lib directory would fix the issue, but I didn&#8217;t want to customize the install.  I was originally using a Scala closure as a job unit, which had no references to the log object.  In theory, if that&#8217;s the unit that gets serialized and sent over the wire, the other end should not have to worry about any logback references, since they aren&#8217;t a part of the serialized closure references.  In my case, that didn&#8217;t work. Somehow the serialization decided to serialize logback related stuff, because the top level class where the closure was being created used the logger.  I&#8217;m not sure if this is a problem with serialization or a leaky abstraction of the JVM and the fact that functions aren&#8217;t first class citizens.  I think the lowest level of serialization is at the class level, though I had to extract it to a class and implement a GridTask instead.  Because GridTask class extension didn&#8217;t reference any logger object, it was serialized as needed and sent over without causing a classpath conflict.  I haven&#8217;t had the time yet to figure out whether it&#8217;s the fault of Gridgain&#8217;s optimized serializer or whether this is a side effect of the JVM (as I mentioned above).  I&#8217;ll try to find some time to test this later.</p><p>Second, Gridgain Community Edition has discovery that works great in a homogeneous topology, but for EC2 (NAT, ephemeral private IP addresses, etc&#8230;), configuration is transient in terms of if any of the things I listed changes, the config must change.  This can be remedied by startup scripts, but Nikita said they&#8217;ll add better support for it in the next version (public IP communication would be a good first step, binding to wildcard interfaces would be a great second).</p><h3>Conclusion</h3><p>Overall we had an awesome experience with Gridgain.  The grid application ran flawlessly during our busiest time of the year (Thanksgiving weekend).  It ran so flawlessly, that this morning, I forgot which boxes it was physically running on.</p><p>I plan on using Gridgain in the future and hopefully utilize their data grid to rewrite our computation system to utilize in memory data/compute collocation (data affinity).</p><p>Nikita, thanks for all the help getting things sorted out in the first few days.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2011/11/our-experience-with-distributed-computing-using-gridgain.html/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Distributed locking made easy</title><link>http://ilyasterin.com/blog/2011/10/distributed-locking-made-easy.html</link> <comments>http://ilyasterin.com/blog/2011/10/distributed-locking-made-easy.html#comments</comments> <pubDate>Mon, 31 Oct 2011 20:21:44 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[algorithms]]></category> <category><![CDATA[distributed]]></category> <category><![CDATA[ruby]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=400</guid> <description><![CDATA[There are various situations when one would use a simple mutex to ensure mutual exclusion to a shared resource. This is usually very simple to accomplish using your favorite language library, but that constrains you to a single process mutual exclusion. Even single machine mutual exclusion is rather straight forward, usually just locking a resource [...]]]></description> <content:encoded><![CDATA[<p>There are various situations when one would use a simple mutex to ensure mutual exclusion to a shared resource.  This is usually very simple to accomplish using your favorite language library, but that constrains you to a single process mutual exclusion.  Even single machine mutual exclusion is rather straight forward, usually just locking a resource (i.e. file) and awaiting for the lock to be released.  You can use that for an IPC mutex.</p><p>But what if one needs a distributed mutex to allow mutual exclusion amongst distributed clients?  At that, the mutex has to offer various guarantees, as is with any shared state.  We know shared state is hard to reason about and provokes a lot of bug-prone software, shared distributed state, is much harder, requiring distributed guaranteed consensus all while operating in a non-reliable network environment.  There are various distributed consensus algorithms, <a href="http://en.wikipedia.org/wiki/Paxos_algorithm">Paxos</a> being one of the more widely used ones.</p><p>But you can deploy your own distributed locking service, without having to implement your own. <a href="http://zookeeper.apache.org/">Apache Zookeeper</a>, offers distributed synchronization and group services.  Mutex/locking is just one of the things you can do with Zookeeper.  Zookeeper is rather low level, so implementing a distributed lock, although trivial, requires some boilerplate.</p><p>Recently we needed a distributed lock service, to ensure only one person in our organization is performing a particular systems activity at any given point and time.  We implemented it on top of a homegrown tool written in ruby.  The example below is in ruby, though the api calls would translate to any language&#8230;</p><div id="gist-1328677" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="s1">&#39;zookeeper&#39;</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="k">class</span> <span class="nc">Lock</span>  </div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="s2">&quot;/my-app&quot;</span><span class="p">)</span>    </div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="vi">@zk</span> <span class="o">=</span> <span class="no">Zookeeper</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">host</span><span class="p">)</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="vi">@root</span> <span class="o">=</span> <span class="n">root</span></div><div class='line' id='LC7'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC8'>&nbsp;&nbsp;</div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">with_lock</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">timeout</span><span class="p">,</span> <span class="n">timeout_callback</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">new_lock_res</span> <span class="o">=</span> <span class="vi">@zk</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="ss">:path</span> <span class="o">=&gt;</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="vi">@root</span><span class="si">}</span><span class="s2">/</span><span class="si">#{</span><span class="n">app</span><span class="si">}</span><span class="s2">-&quot;</span><span class="p">,</span> <span class="ss">:sequence</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">,</span> <span class="ss">:ephemeral</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">)</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">unique_lock_path</span> <span class="o">=</span> <span class="n">new_lock_res</span><span class="o">[</span><span class="ss">:path</span><span class="o">]</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="n">get_lock</span><span class="p">(</span><span class="n">unique_lock_path</span><span class="p">,</span> <span class="n">timeout</span><span class="p">)</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">yield</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="vi">@zk</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="ss">:path</span> <span class="o">=&gt;</span> <span class="n">unique_lock_path</span><span class="p">)</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">else</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">timeout_callback</span><span class="o">.</span><span class="n">call</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC18'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'>&nbsp;&nbsp;<span class="kp">private</span></div><div class='line' id='LC21'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">get_lock</span><span class="p">(</span><span class="n">unique_lock_path</span><span class="p">,</span> <span class="n">timeout</span><span class="p">)</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">lock_key</span> <span class="o">=</span> <span class="n">unique_lock_path</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="sr">/^</span><span class="si">#{</span><span class="no">Regexp</span><span class="o">.</span><span class="n">quote</span><span class="p">(</span><span class="vi">@root</span><span class="p">)</span><span class="si">}</span><span class="sr">\//</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span></div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="mi">0</span><span class="o">.</span><span class="n">.</span><span class="mi">4</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">children</span> <span class="o">=</span> <span class="vi">@zk</span><span class="o">.</span><span class="n">get_children</span><span class="p">(</span><span class="ss">:path</span> <span class="o">=&gt;</span> <span class="vi">@root</span><span class="p">)</span><span class="o">[</span><span class="ss">:children</span><span class="o">].</span><span class="n">sort</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">watcher</span> <span class="o">=</span> <span class="no">Zookeeper</span><span class="o">::</span><span class="no">WatcherCallback</span><span class="o">.</span><span class="n">new</span> <span class="p">{}</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="n">children</span><span class="o">.</span><span class="n">first</span> <span class="o">==</span> <span class="n">lock_key</span><span class="p">)</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kp">true</span></div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">else</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">less_than_path_idx</span> <span class="o">=</span> <span class="p">(</span><span class="n">children</span><span class="o">.</span><span class="n">index</span> <span class="p">{</span><span class="o">|</span><span class="nb">p</span><span class="o">|</span> <span class="nb">p</span> <span class="o">==</span> <span class="n">lock_key</span><span class="p">})</span> <span class="o">-</span> <span class="mi">1</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">stat_res</span> <span class="o">=</span> <span class="vi">@zk</span><span class="o">.</span><span class="n">stat</span><span class="p">(</span><span class="ss">:path</span> <span class="o">=&gt;</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="vi">@root</span><span class="si">}</span><span class="s2">/</span><span class="si">#{</span><span class="n">children</span><span class="o">[</span><span class="n">less_than_path_idx</span><span class="o">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> </div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:watcher</span> <span class="o">=&gt;</span> <span class="n">watcher</span><span class="p">)</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="n">stat_res</span><span class="o">[</span><span class="ss">:stat</span><span class="o">].</span><span class="n">exists</span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">success</span> <span class="o">=</span> <span class="n">wait_until</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span> <span class="p">{</span> <span class="n">watcher</span><span class="o">.</span><span class="n">completed?</span> <span class="p">}</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="o">!</span><span class="n">success</span></div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kp">false</span>            </div><div class='line' id='LC37'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC38'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC39'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC40'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC41'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kp">false</span></div><div class='line' id='LC42'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC43'><br/></div><div class='line' id='LC44'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">wait_until</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">block</span><span class="p">)</span></div><div class='line' id='LC45'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">time_to_stop</span> <span class="o">=</span> <span class="no">Time</span><span class="o">.</span><span class="n">now</span> <span class="o">+</span> <span class="n">timeout</span></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">until</span> <span class="k">yield</span> <span class="k">do</span></div><div class='line' id='LC47'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="no">Time</span><span class="o">.</span><span class="n">now</span> <span class="o">&gt;</span> <span class="n">time_to_stop</span></div><div class='line' id='LC48'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kp">false</span></div><div class='line' id='LC49'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC50'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">sleep</span> <span class="mi">0</span><span class="o">.</span><span class="mi">1</span></div><div class='line' id='LC51'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="kp">true</span></div><div class='line' id='LC53'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC54'><span class="k">end</span></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/1328677/4d3bab5052bd199c8168fdc91a2ba3694cc37a39/gistfile1.rb" style="float:right;">view raw</a> <a href="https://gist.github.com/1328677#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a> <a href="https://gist.github.com/1328677">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>The usage of this Lock class is such:</p><pre><code>    Lock.new("localhost:2181").with_lock(
      "/myapp",
      5, ## Timeout in seconds
      lambda { ## Timeout callback
        abort("Couldn't acquire lock.  Timeout.") },
      lambda { ## Do what ever you want here  }
    )
</code></pre><p>The details of the algorithm are <a href="http://zookeeper.apache.org/doc/r3.1.2/recipes.html#sc_recipes_Locks">outlined here</a>.</p><p>Of course, before you use it, you must <a href="http://zookeeper.apache.org/doc/r3.1.2/zookeeperStarted.html">install Zookeeper</a> and create the root path <em>/myapp</em> in order to be able to use it.</p><p>Also, please note, I have removed the access control part from the example.  In order to use this in production, I strongly encourage you <a href="http://zookeeper.apache.org/doc/r3.1.2/zookeeperProgrammers.html#sc_ZooKeeperAccessControl">read this</a>.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2011/10/distributed-locking-made-easy.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>jconsole/jvisualvm rmi on ec2</title><link>http://ilyasterin.com/blog/2011/09/jconsolejvisualvm-rmi-on-ec2.html</link> <comments>http://ilyasterin.com/blog/2011/09/jconsolejvisualvm-rmi-on-ec2.html#comments</comments> <pubDate>Sat, 24 Sep 2011 13:58:02 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[Java]]></category> <category><![CDATA[jconsole]]></category> <category><![CDATA[jndi]]></category> <category><![CDATA[jvisualvm]]></category> <category><![CDATA[rmi]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=392</guid> <description><![CDATA[I finally figured this out, thanks to Google of course. No single post or documentation solved the issue, but after a 2 hour battle and various options, I finally have it working. If you are running a java app on ec2 and want to remotely connect to it using jconsole or jvisualvm, you need to [...]]]></description> <content:encoded><![CDATA[<p>I finally figured this out, thanks to Google of course.  No single post or documentation solved the issue, but after a 2 hour battle and various options, I finally have it working.</p><p>If you are running a java app on ec2 and want to remotely connect to it using jconsole or jvisualvm, you need to start your java app with a few options.  Here is my configuration.  Also, note that disabling authentication, opens this up for everyone.  Not good, so don&#8217;t do this in production or on a box that matters.  Also, this doesn&#8217;t work with a restrictive firewall.  Since RMI port is chosen randomly, you must have a rather loose firewall policy.  There are ways around it, with ssh tunneling I believe, but this post won&#8217;t cover it as this point, I might do it at some point later.</p><p>First you need a policy file.  Again this can be fine tuned, the example below shows a dangerously loose one&#8230;</p><pre><code>grant {
  permission java.security.AllPermission;
};
</code></pre><p>Place this file in some directory.  In my example it&#8217;s sitting in my home dir and is named .java.policy</p><pre><code>java -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9001 \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Djava.security.policy=.java.policy \
  -Dcom.sun.management.jmxremote.local.only=false \
  -Djava.rmi.server.hostname=your.public.hostname.com \
  -jar test.jar Runner
</code></pre><p>This starts the app and an jndi service listening on port 9001.</p><p>In jvisualvm, you now can connect to <em>your.public.hostname.com:9001</em>.  You can tune your parameters as needed, but two are crucial in my experience: <code>com.sun.management.jmxremote.local.only</code> and <code>java.rmi.server.hostname</code>.  I had to specify these in order to make things work.  Your mileage may vary.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2011/09/jconsolejvisualvm-rmi-on-ec2.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Netcap TCP/IP sniffing (proxy)</title><link>http://ilyasterin.com/blog/2011/08/netcap-tcpip-sniffing-proxy.html</link> <comments>http://ilyasterin.com/blog/2011/08/netcap-tcpip-sniffing-proxy.html#comments</comments> <pubDate>Wed, 31 Aug 2011 01:11:36 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[linux]]></category> <category><![CDATA[tcp/ip]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=379</guid> <description><![CDATA[I find myself lately doing a lot of raw TCP/IP stuff and had a need today to look at a protocol. I know there is Wireshark and similar utilities, but I needed to do something on a remote server, by creating a reverse proxy in order to learn the ins and outs of a custom [...]]]></description> <content:encoded><![CDATA[<p>I find myself lately doing a lot of raw TCP/IP stuff and had a need today to look at a protocol.  I know there is Wireshark and similar utilities, but I needed to do something on a remote server, by creating a reverse proxy in order to learn the ins and outs of a custom protocol.</p><p>The below command creates a proxy and writes the protocol to files&#8230;</p><pre><code>mknode /tmp/backpipe p

nc -l 61610 0&lt;/tmp/backpipe | \
tee -a /tmp/inflow | \
nc localhost 61611 | \
tee -a /tmp/outflow 1&gt;/tmp/backpipe
</code></pre><p>In this case the server listens to port 61610 and then forwards the incoming packets to localhost:61611.  You  should modify the ports and forward host/port to what ever suits your need.  Now, if you point the connection of any device to your server&#8217;s 61610 port, you can tail /tmp/inflow and /tmp/outflow to see the protocol communications, you can tail both together with&#8230;</p><pre><code>tail -f /tmp/inflow /tmp/outflow
</code></pre><p>If you are on Mac OS X, in order to create a fifo file, you should replace the <code>mknode</code> command with&#8230;</p><pre><code>mkfifo /tmp/backpipe
</code></pre>]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2011/08/netcap-tcpip-sniffing-proxy.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>On startups and innovation</title><link>http://ilyasterin.com/blog/2011/02/on-startups-and-innovation.html</link> <comments>http://ilyasterin.com/blog/2011/02/on-startups-and-innovation.html#comments</comments> <pubDate>Fri, 11 Feb 2011 00:19:08 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[Startups]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=352</guid> <description><![CDATA[Throughout my career I&#8217;ve worked at numerous organizations, large and small. Last 5 years I&#8217;ve spent doing startups, the previous years were spent at large companies. I prefer small organizations, specifically startup environments, for reasons I&#8217;ll discuss later. There is something that can be learned, good and bad, from both types of organizations. I&#8217;ll start [...]]]></description> <content:encoded><![CDATA[<p>Throughout my career I&#8217;ve worked at numerous organizations, large and small.  Last 5 years I&#8217;ve spent doing startups, the previous years were spent at large companies.  I prefer small organizations, specifically startup environments, for reasons I&#8217;ll discuss later. There is something that can be learned, good and bad, from both types of organizations.  I&#8217;ll start with some positives.</p><h4>Startups</h4><p>I&#8217;m going to use the word &#8220;startup&#8221; to not only refer to companies that are just launching or haven&#8217;t been around for a while. In my opinion startup is now synonymous with a company that operates like one.  They are always in launch mode, always looking for new adventures and opportunities, and always innovating.</p><p>Not all small companies are startups.  Many small companies have been around long enough to amass some or many startup antipatterns, which is in most cases rather detrimental to its growth.  Large organizations can bear some of these antipatterns for years, as they lurke and hide behind large bureaucracies and/or residual revenues.  Large organizations also have different priorities.</p><p>Startups are the innovation backbone in this country and others. Their beginnings usually involve individuals who have knowledge and experience in a particular area and/or they see a need to fill a gap. Sometimes it&#8217;s not a gap, in terms of a complete void, rather it&#8217;s a gap in terms of doing something better.  These individuals are motivated by their idea and the vision of making a world (as they see it) a better place, glory, recognition, etc&#8230;  There is also monetary motivation, but the product or service motivation is usually higher (at least in the ones that succeed).  Also, there is drive and the drive has to be strong.  I mean, in lots of cases, these individuals give up good paying jobs and benefits, put their quality of life and possibly the quality of life of others in jeopardy, without any guarantees, all for this dream.  A lot of these folks have worked at other companies and they&#8217;ve decided that they can form a successful team and eventually bear the fruits of their labor (again not only in monetary compensation).  Wow, that&#8217;s inspirational and also&#8230; &#8220;scary&#8221;.</p><p>During the initial stages of the startup, there is no time for bullshit.  The bureaucracy and overhead that plagues established companies has to go.  They have to get shit done, they have to do it good, and they have to do it fast.  They don&#8217;t want to rush to sacrifice quality, since this is the reason they formed this alliance, to create a &#8220;quality&#8221; product, better than their competitors.  This is also the time when creativity is at its highest.  How else can you stay in business when you&#8217;re competing with a company that has 10 times as many employees, has been adding features for years, has an established brand, and more money.</p><p>Now the more technical side (I&#8217;m mostly writing about tech startups here, as this is what I&#8217;m more familiar with).</p><p>There are many things to do, design, architecture, programming, testing, deployment, etc&#8230;  Choices need to be made and these choices have different priorities than in large companies.  Stuff has to be done fast, so there is no time for the &#8220;Enterprise&#8221; stuff.  Whatever that word at one point signified, it&#8217;s now become synonymous with &#8220;clueless pointy hairy bosses&#8221;.  There is not time for commercial product evaluation, negotiations, and life cycles. Open Source Software usually rules in successful startups.  It allows them to benefit from quality code with the ability to resolve bugs, add features and augment the software as they wish.  They often built software using open source platforms and frameworks and themselves greatly contribute to open source.  Many times the tools that they built, that aren&#8217;t specific to their business and don&#8217;t contain any intellectual property, are released to benefit the community.  Now others can use that as a tool to benefit in their endeavor.  The cycle continues.</p><p>I&#8217;m going to refrain from discussing specific examples of what I&#8217;d consider sensible choices.  Every business and motivation has different priorities and in many cases what I would consider a suboptimal choice, would actually be the best choice for a task/dilemma at hand. One thing&#8217;s for sure though, open source software rules and beyond the brilliant people that make things happen, is a big contributor to the success of these companies.</p><p>Because people are smart, they have to get things done, and they put their blood and sweat into it, they take their time to create fun and productive environments.  I mean, who wants to work a lot and not have fun doing it?  Or who wants to give up the security of a full time job to fail?</p><h4>Large companies</h4><p>So I actually won&#8217;t talk about large companies here.  I use the name mostly to refer to practices that are prevalent in larger organizations.  I&#8217;m mostly going to look at the shift from an efficient, fun startup, to a bureaucratic mind draining organization that has lost its ways.</p><p>This happens all the time.  The talent looses its interest and usually scatters to other companies or to start their own.  The company is left with a product that&#8217;s aging and a leadership team that&#8217;s focused on maximizing the profit from the product it has.  Nothing wrong with maximizing the profit, but not at the cost of stagnation.  The talent drain is prevailing and the leadership for the lack of better judgment blames this on the lack of a process.  &#8220;We&#8217;ve lost our ways, we&#8217;re not productive any more.  We need to put a process in place that will get us going.&#8221;  they say.  I&#8217;m not going to judge these folks at this point, I mean their core competency isn&#8217;t innovation, it&#8217;s stability.  The two are polar opposites.</p><p>Then havoc wreaks. Process after process is established; Feature after feature thoughtlessly gets added to the product; Documentation and processes take priority to common sense and productivity; Code base grows unmanageable; More time is spent talking about doing, than doing.  Sometimes more and more people get hired, with less and less qualifications or for qualifications that aren&#8217;t critical to success. Sounds familiar?</p><p>This happens all the time.  The bottom line is that most innovators don&#8217;t spend their lifetime chasing an idea (especially these days). They innovate and then when they don&#8217;t see any more room for innovation and fun, they leave.  Yes, they have what some would call ADHD when it comes to stability and work ethics.  They probably do, but in a good form, they are chasing their dreams and refuse to waste time on something that won&#8217;t make them happy.</p><p>This is not to say that innovators are better than &#8220;stabilizers&#8221; (I just made that one up).  There is room for both, but stabilizers need to understand how to maintain the level of competitiveness and innovative spirit in the organizations. They should recruit and motivate the brightest, not the workaholics per say, not the conformists, but free spirited minds.  These are the folks that make shit happen.  These folks of course have to be kept in check by the stabilizers, but not by getting in their way.  Actually, the total opposite, by getting out of their way.  Give them room to do what they do best.</p><h4>Conclusion</h4><p>I don&#8217;t think it&#8217;s ever too late for a company to change its ways. Get back to a startup environment.  Large organizations might have a hard time doing this.  They have too many people and they can&#8217;t just start over.  Small companies are great for this.  They can start afresh. They can retain talent, pay them well, make them happy, and most of all, I&#8217;ll say it again, get out of their way.  If you hired a development team to create a product, let them do it.  The more shackles you put on them, the less likely they&#8217;ll succeed and the more likely they&#8217;ll leave ASAP.  Intellectuals are always in demand and it really bothers me to see companies treat such employees as sweat shop workers.  We pay you, you do as you&#8217;re told.  That&#8217;s a recipe for disaster.</p><p>If your developers are more productive with language <em>x</em> and platform <em>y</em>, unless their choice is completely ridiculous, let them use it. They&#8217;ll thank you later, with a better quality product, more productivity and generally a more positive attitude.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2011/02/on-startups-and-innovation.html/feed</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Merge sort in lisp</title><link>http://ilyasterin.com/blog/2011/02/merge-sort-in-lisp.html</link> <comments>http://ilyasterin.com/blog/2011/02/merge-sort-in-lisp.html#comments</comments> <pubDate>Thu, 10 Feb 2011 20:36:18 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[algorithms]]></category> <category><![CDATA[lisp]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=345</guid> <description><![CDATA[I&#8217;m currently taking (online) MIT&#8217;s algorithms course. I needed a good brush-up on algorithms, starting with the basic theory. I&#8217;m going to jump in to help a buddy working on a graph database in lisp Vivace Graph, which should be an open source competitor to AllegroGraph. Allegro has probably the best graph db out there [...]]]></description> <content:encoded><![CDATA[<p>I&#8217;m currently taking (online) MIT&#8217;s algorithms course.  I needed a good brush-up on algorithms, starting with the basic theory.  I&#8217;m going to jump in to help a buddy working on a graph database in lisp <a href="https://github.com/kraison/vivace-graph-v2">Vivace Graph</a>, which should be an open source competitor to AllegroGraph.  Allegro has probably the best graph db out there right now.  There are some competitors in the java world, but they are either expensive or don&#8217;t provide enough features, or don&#8217;t provide APIs outside of java.  Allegro has an extensive list of client libs.  I&#8217;ll write up more on the graph db in some future, for now, I got back into lisp and implemented the simplest alg (merge sort) in it.</p><p>The reason I&#8217;m posting is to get some comments.  I&#8217;d love to hear your thoughts on how a lisp nOOb can improve this <img src='http://ilyasterin.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /></p><div id="gist-821271" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="p">(</span><span class="nb">defun</span> <span class="nv">merge-sort</span> <span class="p">(</span><span class="nv">lst</span><span class="p">)</span></div><div class='line' id='LC2'>&nbsp;&nbsp;<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">size</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">lst</span><span class="p">)))</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">=</span> <span class="nv">size</span> <span class="mi">1</span><span class="p">)</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">lst</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">progn</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">seq1</span> <span class="p">(</span><span class="nv">merge-sort</span> <span class="p">(</span><span class="nb">subseq</span> <span class="nv">lst</span> <span class="mi">0</span> <span class="p">(</span><span class="nb">floor</span> <span class="p">(</span><span class="nb">/</span> <span class="nv">size</span> <span class="mi">2</span><span class="p">)))))</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nv">seq2</span> <span class="p">(</span><span class="nv">merge-sort</span> <span class="p">(</span><span class="nb">subseq</span> <span class="nv">lst</span> <span class="p">(</span><span class="nb">floor</span> <span class="p">(</span><span class="nb">/</span> <span class="nv">size</span> <span class="mi">2</span><span class="p">))</span> <span class="nv">size</span><span class="p">))))</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nv">merge-it</span> <span class="nv">seq1</span> <span class="nv">seq2</span><span class="p">))))))</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="p">(</span><span class="nb">defun</span> <span class="nv">merge-it</span> <span class="p">(</span><span class="nv">l1</span> <span class="nv">l2</span><span class="p">)</span></div><div class='line' id='LC12'>&nbsp;&nbsp;<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">new-arr</span> <span class="p">(</span><span class="nb">make-array</span> <span class="p">(</span><span class="nb">+</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">l1</span><span class="p">)</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">length</span> <span class="nv">l2</span><span class="p">))</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="ss">:fill-pointer</span> <span class="mi">0</span><span class="p">)))</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">loop</span> <span class="nv">for</span> <span class="nv">idx</span> <span class="nv">from</span> <span class="mi">0</span> <span class="nv">to</span> <span class="p">(</span><span class="nb">+</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">l1</span><span class="p">)</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">l2</span><span class="p">))</span> <span class="nb">do</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">x</span> <span class="p">(</span><span class="nb">car</span> <span class="nv">l1</span><span class="p">))</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nv">y</span> <span class="p">(</span><span class="nb">car</span> <span class="nv">l2</span><span class="p">)))</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">not</span> <span class="p">(</span><span class="nb">null</span> <span class="nv">x</span><span class="p">))</span> <span class="p">(</span><span class="nb">not</span> <span class="p">(</span><span class="nb">null</span> <span class="nv">y</span><span class="p">)))</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">&lt;=</span> <span class="nv">x</span> <span class="nv">y</span><span class="p">)</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">progn</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">setf</span> <span class="nv">l1</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">l1</span><span class="p">))</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">vector-push</span> <span class="nv">x</span> <span class="nv">new-arr</span><span class="p">))</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="k">progn</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">setf</span> <span class="nv">l2</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">l2</span><span class="p">))</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">vector-push</span> <span class="nv">y</span> <span class="nv">new-arr</span><span class="p">))))))</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">mapcar</span> <span class="nf">#&#39;</span><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">e</span><span class="p">)</span> <span class="p">(</span><span class="nb">vector-push</span> <span class="nv">e</span> <span class="nv">new-arr</span><span class="p">))</span> <span class="p">(</span><span class="nb">append</span> <span class="nv">l1</span> <span class="nv">l2</span><span class="p">))</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">(</span><span class="nb">coerce</span> <span class="nv">new-arr</span> <span class="ss">&#39;list</span><span class="p">)))</span></div><div class='line' id='LC28'><br/></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/821271/8cbbee2af6470b81c967290cce1233e44aa9286f/mergesort.lisp" style="float:right;">view raw</a> <a href="https://gist.github.com/821271#file_mergesort.lisp" style="float:right;margin-right:10px;color:#666">mergesort.lisp</a> <a href="https://gist.github.com/821271">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div>]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2011/02/merge-sort-in-lisp.html/feed</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Rails custom validation before ActiveRecord typecasting</title><link>http://ilyasterin.com/blog/2010/12/rails-custom-validation-before-activerecord-typecasting.html</link> <comments>http://ilyasterin.com/blog/2010/12/rails-custom-validation-before-activerecord-typecasting.html#comments</comments> <pubDate>Mon, 13 Dec 2010 23:18:30 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[rails]]></category> <category><![CDATA[ruby]]></category> <category><![CDATA[ruby on rails]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=333</guid> <description><![CDATA[Rails 3 validation framework, extracted from ActiveRecord and now a part of ActiveModel is pretty sleek. As anything else rails (consider it good or bad) it offers sensible defaults. Most stuff in rails is also easily configurable/customizable. Validations is one such thing, but I think it needs more documentation. I ran into a problem trying [...]]]></description> <content:encoded><![CDATA[<p>Rails 3 validation framework, extracted from ActiveRecord and now a part of ActiveModel is pretty sleek. As anything else rails (consider it good or bad) it offers sensible defaults.  Most stuff in rails is also easily configurable/customizable.  Validations is one such thing, but I think it needs more documentation.</p><p>I ran into a problem trying to validate a date field (defined in ActiveRecord) as:</p><div id="gist-739725" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="k">class</span> <span class="nc">CreateAssets</span> <span class="o">&lt;</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span></div><div class='line' id='LC2'>&nbsp;&nbsp;<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">up</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">create_table</span> <span class="ss">:assets</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">t</span><span class="o">.</span><span class="n">date</span> <span class="ss">:manufacturing_date</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'><span class="o">.</span><span class="n">.</span><span class="o">.</span><span class="n">.</span><span class="o">.</span></div><div class='line' id='LC7'><br/></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/739725/60c65f8b4b6a9f1d4e26545895e540388929192a/gistfile1.rb" style="float:right;">view raw</a> <a href="https://gist.github.com/739725#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a> <a href="https://gist.github.com/739725">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>Rails also doesn&#8217;t have a built-in date validation, but it&#8217;s easy enough to either provide your own validator method or create a reusable validator.  I opted for the later, as I might need to reuse the same validator across the site.</p><div id="gist-740975" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="s1">&#39;chronic&#39;</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="k">class</span> <span class="nc">DateValidator</span> <span class="o">&lt;</span> <span class="no">ActiveModel</span><span class="o">::</span><span class="no">EachValidator</span></div><div class='line' id='LC4'>&nbsp;&nbsp;</div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">validate_each</span><span class="p">(</span><span class="n">record</span><span class="p">,</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">valid</span> <span class="o">=</span> <span class="kp">true</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">begin</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">y</span> <span class="o">=</span> <span class="no">Chronic</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">value</span><span class="p">)</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">valid</span> <span class="o">=</span> <span class="kp">false</span> <span class="k">unless</span> <span class="n">y</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">rescue</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">valid</span> <span class="o">=</span> <span class="kp">false</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span>   </div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">record</span><span class="o">.</span><span class="n">errors</span><span class="o">[</span><span class="n">attribute</span><span class="o">]</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="n">options</span><span class="o">[</span><span class="ss">:message</span><span class="o">]</span> <span class="o">||</span> <span class="s2">&quot;is not a valid date&quot;</span><span class="p">)</span> <span class="k">unless</span> <span class="n">valid</span>  </div><div class='line' id='LC14'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC15'><span class="k">end</span></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/740975/d481c416f2d4006e483f938a3a3d9e6c8b019b8b/gistfile1.rb" style="float:right;">view raw</a> <a href="https://gist.github.com/740975#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a> <a href="https://gist.github.com/740975">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>So running this with any invalid date value, like say <em>11111111111</em> which gets parsed by <em>Date.parse</em> method didn&#8217;t yield an error, actually it never even invoked the validator.</p><p>After a bit of digging, I figured out that it has to do with the lifecycle of ActiveRecord, basically it tries to typecast the value to the value defined in migrations.  Typecasting invalid values like above causes ActiveRecord to set the value to nil (not sure why yet, will dig into source code later). Because the validator isn&#8217;t invoked on nil values, unless you specifically tell it to not allow nil with <em>:allow_nil => false</em>, the <em>validate&#95;each</em> method is bypassed.  You can see the logic for yourself in the <a href="http://edgeapi.rubyonrails.org/classes/ActiveModel/EachValidator.html#method-i-validate"><em>validate</em></a> method.</p><p>In order to fix this issue, you have to access the raw value that&#8217;s kept around after the typecast.  I turned this into a reusable class, though if the validator that needs to operate on the raw (uncasted) value, you just inherit from this class.  Here is the class&#8230;</p><div id="gist-739773" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="k">class</span> <span class="nc">RawEachValidator</span> <span class="o">&lt;</span> <span class="no">ActiveModel</span><span class="o">::</span><span class="no">EachValidator</span></div><div class='line' id='LC2'>&nbsp;&nbsp;</div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">validate</span><span class="p">(</span><span class="n">record</span><span class="p">)</span>                                     </div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">attributes</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">attribute</span><span class="o">|</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">raw_value</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="n">attribute</span><span class="si">}</span><span class="s2">_before_type_cast&quot;</span><span class="p">)</span> <span class="o">||</span> <span class="n">record</span><span class="o">.</span><span class="n">read_attribute_for_validation</span><span class="p">(</span><span class="n">attribute</span><span class="p">)</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">self</span><span class="o">.</span><span class="n">validate_each</span><span class="p">(</span><span class="n">record</span><span class="p">,</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">raw_value</span><span class="p">)</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC8'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC9'>&nbsp;&nbsp;</div><div class='line' id='LC10'><span class="k">end</span></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/739773/955d256906e6d562d253ed056824c18cab914538/gistfile1.rb" style="float:right;">view raw</a> <a href="https://gist.github.com/739773#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a> <a href="https://gist.github.com/739773">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>Now the <em>DataValidator</em> above just need to inherit from RawEachValidator and you&#8217;re all set.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2010/12/rails-custom-validation-before-activerecord-typecasting.html/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Learning Haskell (Part 1)</title><link>http://ilyasterin.com/blog/2010/10/learning-haskell-part-1.html</link> <comments>http://ilyasterin.com/blog/2010/10/learning-haskell-part-1.html#comments</comments> <pubDate>Thu, 28 Oct 2010 19:50:33 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[FP]]></category> <category><![CDATA[functional programming]]></category> <category><![CDATA[haskell]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=328</guid> <description><![CDATA[So my friend Davis Ford decided to start a Haskell study group in Grosse Pointe, MI. Our first meeting was yesterday, and 4 people attended. This isn&#8217;t bad, considering that most IT folks don&#8217;t live nearby and the fact that it&#8217;s Haskell . I think we might be able to get 6+ at the next [...]]]></description> <content:encoded><![CDATA[<p>So my friend <a href="http://www.zenoconsulting.biz/Welcome.html">Davis Ford</a> decided to start a <a href="http://groups.google.com/group/detroit-haskell">Haskell study group</a> in Grosse Pointe, MI.  Our first meeting was yesterday, and 4 people attended.  This isn&#8217;t bad, considering that most IT folks don&#8217;t live nearby and the fact that it&#8217;s Haskell <img src='http://ilyasterin.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .  I think we might be able to get 6+ at the next meeting and hopefully more at some point.</p><p>We had a really good start yesterday.  We decided to read Ch. 1-4 of <a href="http://learnyouahaskell.com/">LearnYouAHaskell</a> before the meeting and then discuss the relevant topics.  Here are some of the n00b things we talked about:</p><ul><li>function declarations and definitions</li><li>function argument destructuring and polymorphic dispatch</li><li>implemented recursive product function and quick sort</li><li>logging, which turned into having pure/impure function mixture</li></ul><p>So our quicksort implementations turned out to be such:</p><div id="gist-652169" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="c1">-- Product function</span></div><div class='line' id='LC2'><span class="nf">product&#39;</span> <span class="kt">[]</span> <span class="ow">=</span> <span class="mi">1</span></div><div class='line' id='LC3'><span class="nf">product&#39;</span> <span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span> <span class="ow">=</span> </div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="kr">do</span> <span class="n">putStrLn</span> <span class="s">&quot;testing&quot;</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">return</span> <span class="p">((</span><span class="n">product&#39;</span> <span class="n">xs</span><span class="p">)</span> <span class="o">*</span> <span class="n">x</span><span class="p">)</span></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'><span class="c1">-- quicksort function using where clause</span></div><div class='line' id='LC8'><span class="nf">qsort</span> <span class="kt">[]</span> <span class="ow">=</span> <span class="kt">[]</span></div><div class='line' id='LC9'><span class="nf">qsort</span> <span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span> <span class="ow">=</span> <span class="n">qsort</span> <span class="n">smaller</span> <span class="o">++</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">++</span> <span class="n">qsort</span> <span class="n">larger</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kr">where</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">smaller</span> <span class="ow">=</span> <span class="p">[</span><span class="n">a</span> <span class="o">|</span> <span class="n">a</span> <span class="ow">&lt;-</span> <span class="n">xs</span><span class="p">,</span> <span class="n">a</span> <span class="o">&lt;=</span> <span class="n">x</span><span class="p">]</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">larger</span> <span class="ow">=</span> <span class="p">[</span><span class="n">b</span> <span class="o">|</span> <span class="n">b</span> <span class="ow">&lt;-</span> <span class="n">xs</span><span class="p">,</span> <span class="n">b</span> <span class="o">&gt;</span> <span class="n">x</span><span class="p">]</span></div><div class='line' id='LC13'><br/></div><div class='line' id='LC14'><span class="c1">-- reverse quicksort function</span></div><div class='line' id='LC15'><span class="nf">rqsort</span> <span class="kt">[]</span> <span class="ow">=</span> <span class="kt">[]</span></div><div class='line' id='LC16'><span class="nf">rqsort</span> <span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span> <span class="ow">=</span> <span class="n">rqsort</span> <span class="p">(</span><span class="n">rqsort</span> <span class="n">larger</span><span class="p">)</span> <span class="o">++</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">++</span> <span class="n">smaller</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kr">where</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">smaller</span> <span class="ow">=</span> <span class="p">[</span><span class="n">a</span> <span class="o">|</span> <span class="n">a</span> <span class="ow">&lt;-</span> <span class="n">xs</span><span class="p">,</span><span class="n">a</span> <span class="o">&lt;=</span> <span class="n">x</span><span class="p">]</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">larger</span> <span class="ow">=</span> <span class="p">[</span><span class="n">b</span> <span class="o">|</span> <span class="n">b</span> <span class="ow">&lt;-</span> <span class="n">xs</span><span class="p">,</span><span class="n">b</span> <span class="o">&gt;</span> <span class="n">x</span><span class="p">]</span></div><div class='line' id='LC20'><br/></div><div class='line' id='LC21'><span class="c1">-- quicksort done using filters vs. where clause</span></div><div class='line' id='LC22'><span class="nf">qsort&#39;</span> <span class="kt">[]</span> <span class="ow">=</span> <span class="kt">[]</span></div><div class='line' id='LC23'><span class="nf">qsort&#39;</span> <span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span> <span class="ow">=</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o">&lt;</span> <span class="n">x</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span> <span class="o">++</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">++</span> <span class="n">qsort&#39;</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o">&gt;=</span> <span class="n">x</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span>       </div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/652169/ce79f53d92cb9e2640ab4aa96f4cd187ae2c5de8/gistfile1.hs" style="float:right;">view raw</a> <a href="https://gist.github.com/652169#file_gistfile1.hs" style="float:right;margin-right:10px;color:#666">gistfile1.hs</a> <a href="https://gist.github.com/652169">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>One thing that I still haven&#8217;t concretely figured out is the fourth bullet point, logging.  Basically I wanted to perform logging while say calculating a product.  Evidently you can either have a destructive function, which performs/returns IO operation(s), or a pure function.  Mixing both doesn&#8217;t seem to work.</p><p>Something as simple as:</p><p><pre>
printSomething' = do 
  putStrLn "test"
  return (1 + 1)
</pre></p><p>Didn&#8217;t work, yielding this error:</p><p><pre>
Occurs check: cannot construct the 
infinite type: b = IO b
      Expected type: b
      Inferred type: IO b
    In the first argument of <code>return', 
    namely</code>((product' xs) * x)'
    In the expression: return ((product' xs) * x)
</pre></p><p>I was able to find information discussing doing this through an IO Monad, but am yet to actually construct a working example.  Seems like too much work for something as simple, but it might just be that I&#8217;m misunderstanding something due to lack of Haskell knowledge.  Off to learn more this week and I&#8217;ll post a working hybrid function example once I get it worked out.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2010/10/learning-haskell-part-1.html/feed</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>State machine with Clojure macros and runtime argument inference</title><link>http://ilyasterin.com/blog/2010/10/state-machine-with-clojure-macros-and-runtime-argument-inference.html</link> <comments>http://ilyasterin.com/blog/2010/10/state-machine-with-clojure-macros-and-runtime-argument-inference.html#comments</comments> <pubDate>Mon, 25 Oct 2010 21:10:47 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[clojure]]></category> <category><![CDATA[Java]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=320</guid> <description><![CDATA[I few years ago, before I delved into functional programming, I had a small stint with Flex/ActionScript. ActionScript is an imperative language very similar to Java. At the time, I needed a very simple state machine, which had a single path of execution (basically a chain of commands). The design included a chain object, which [...]]]></description> <content:encoded><![CDATA[<p>I few years ago, before I delved into functional programming, I had a small stint with Flex/ActionScript.  ActionScript is an imperative language very similar to Java.  At the time, I needed a very simple state machine, which had a single path of execution (basically a chain of commands).  The design included a chain object, which joined command objects and executed them sequentially as long as no exceptions where thrown.  Because these chains where also used for transformations and had dependencies (one command might compute something that is needed by another command), the commands had to keep state, though a global context object was used to store/retrieve state.  I&#8217;m sure there are other ways of designing such a system, but it turned out to be pretty maintainable and rather clean.  One thing that bothered me at the time were the implicit dependencies amongst the command objects, which relied on certain context information to be there in forms of map keys, which means if a command changed how it stored a particular results, its dependents would have to be modified as well.  Because of the lack of static typing and runtime inference (unless done at each command object level), there was no way to ensure that something wasn&#8217;t silently failing.  The problem was due to utilization of map structures for context storage which besides not having any static typing abilities, also didn&#8217;t allow the chain invocations to perform runtime inference of argument matching.  The implementation was very functional and wasn&#8217;t too badly designed, but definitely not very pretty.</p><p>I don&#8217;t have access to the exact code at this time, but below is a simple example that demonstrated similar issue in Java.</p><div id="gist-645723" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="kn">import</span> <span class="nn">java.util.*</span><span class="o">;</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ChainDemo</span> <span class="o">{</span></div><div class='line' id='LC4'>&nbsp;&nbsp;</div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="kd">static</span> <span class="kd">interface</span> <span class="nc">Command</span> <span class="o">{</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kt">void</span> <span class="nf">execute</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="n">ctx</span><span class="o">);</span></div><div class='line' id='LC7'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC8'><br/></div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="kd">static</span> <span class="kd">class</span> <span class="nc">Chain</span> <span class="o">{</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">private</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">Command</span><span class="o">&gt;</span> <span class="n">commands</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">Command</span><span class="o">&gt;();</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">addCommand</span><span class="o">(</span><span class="n">Command</span> <span class="n">cmd</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">commands</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">cmd</span><span class="o">);</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span>                   </div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">execute</span><span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="n">ctx</span> <span class="o">=</span> <span class="k">new</span> <span class="n">HashMap</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;();</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">for</span> <span class="o">(</span><span class="n">Command</span> <span class="n">cmd</span> <span class="o">:</span> <span class="n">commands</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">cmd</span><span class="o">.</span><span class="na">execute</span><span class="o">(</span><span class="n">ctx</span><span class="o">);</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC24'>&nbsp;&nbsp;<span class="o">}</span>  </div><div class='line' id='LC25'>&nbsp;&nbsp;</div><div class='line' id='LC26'>&nbsp;&nbsp;<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Chain</span> <span class="n">chain</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Chain</span><span class="o">();</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">chain</span><span class="o">.</span><span class="na">addCommand</span><span class="o">(</span><span class="k">new</span> <span class="n">Command</span><span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">execute</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// Perform some calc here</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">ctx</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">&quot;result1&quot;</span><span class="o">,</span> <span class="mi">1234</span><span class="o">);</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">});</span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">chain</span><span class="o">.</span><span class="na">addCommand</span><span class="o">(</span><span class="k">new</span> <span class="n">Command</span><span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">execute</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kt">int</span> <span class="n">res</span> <span class="o">=</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">ctx</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">&quot;result1&quot;</span><span class="o">);</span></div><div class='line' id='LC37'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">ctx</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">&quot;result2&quot;</span><span class="o">,</span> <span class="n">res</span> <span class="o">*</span> <span class="mi">2</span><span class="o">);</span></div><div class='line' id='LC38'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC39'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">});</span></div><div class='line' id='LC40'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">chain</span><span class="o">.</span><span class="na">addCommand</span><span class="o">(</span><span class="k">new</span> <span class="n">Command</span><span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC41'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">execute</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC42'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">System</span><span class="o">.</span><span class="na">err</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&quot;Results: &quot;</span><span class="o">);</span></div><div class='line' id='LC43'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">for</span> <span class="o">(</span><span class="n">String</span> <span class="n">key</span> <span class="o">:</span> <span class="n">ctx</span><span class="o">.</span><span class="na">keySet</span><span class="o">())</span> <span class="o">{</span></div><div class='line' id='LC44'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">System</span><span class="o">.</span><span class="na">err</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">&quot;\t&quot;</span> <span class="o">+</span> <span class="n">key</span> <span class="o">+</span> <span class="s">&quot;: &quot;</span> <span class="o">+</span> <span class="n">ctx</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">key</span><span class="o">));</span></div><div class='line' id='LC45'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC47'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">});</span></div><div class='line' id='LC48'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">chain</span><span class="o">.</span><span class="na">execute</span><span class="o">();</span></div><div class='line' id='LC49'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'><span class="o">}</span>             </div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/b02a73875601c8fc27f8/9ea4d64e4c212c800790cfbadee877ca89e2e80e/gistfile1.java" style="float:right;">view raw</a> <a href="https://gist.github.com/b02a73875601c8fc27f8#file_gistfile1.java" style="float:right;margin-right:10px;color:#666">gistfile1.java</a> <a href="https://gist.github.com/b02a73875601c8fc27f8">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>Running the above yields:</p><p><pre>
Results: 
    result1: 1234
    result2: 2468
</pre></p><p>Besides the mandatory java ceremony, it&#8217;s also not apparent to me that this can be accomplished any better without the use of reflection, which of course would add yet more boilerplate.</p><p>Macros to the rescue.  If any of you aren&#8217;t familiar with what makes lisp (besides its simple syntax allure) so powerful, you should familiarize yourself with macros.  The example I give below doesn&#8217;t even make a dent into the possibilities of macros.</p><p>With a simple macro</p><div id="gist-645721" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="p">(</span><span class="nf">defmacro</span><span class="w"> </span><span class="nv">make-cmd</span><span class="w"> </span><span class="p">[</span><span class="nv">args</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="nv">body</span><span class="p">]</span><span class="w"></span></div><div class='line' id='LC2'><span class="w">  </span><span class="o">`</span><span class="p">(</span><span class="nf">fn</span><span class="w"> </span><span class="p">[{</span><span class="no">:keys</span><span class="w"> </span><span class="p">[</span><span class="o">~@</span><span class="nv">args</span><span class="p">]</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="nv">ctx</span><span class="o">#</span><span class="p">}]</span><span class="w"></span></div><div class='line' id='LC3'><span class="w">     </span><span class="p">(</span><span class="nf">doseq</span><span class="w"> </span><span class="p">[</span><span class="nv">ar</span><span class="o">#</span><span class="w"> </span><span class="p">[</span><span class="o">~@</span><span class="p">(</span><span class="nf">map</span><span class="w"> </span><span class="nv">keyword</span><span class="w"> </span><span class="nv">args</span><span class="p">)]]</span><span class="w"></span></div><div class='line' id='LC4'><span class="w">       </span><span class="p">(</span><span class="nf">if</span><span class="w"> </span><span class="p">(</span><span class="nf">not</span><span class="w"> </span><span class="p">(</span><span class="nf">contains?</span><span class="w"> </span><span class="nv">ctx</span><span class="o">#</span><span class="w"> </span><span class="nv">ar</span><span class="o">#</span><span class="p">))</span><span class="w"></span></div><div class='line' id='LC5'><span class="w">         </span><span class="p">(</span><span class="nf">throw</span><span class="w"> </span><span class="p">(</span><span class="nf">Exception.</span><span class="w"> </span><span class="p">(</span><span class="nf">str</span><span class="w"> </span><span class="s">&quot;&#39;&quot;</span><span class="w"> </span><span class="p">(</span><span class="nf">name</span><span class="w"> </span><span class="nv">ar</span><span class="o">#</span><span class="p">)</span><span class="w"> </span><span class="s">&quot;&#39; argument is required!&quot;</span><span class="p">)))))</span><span class="w"></span></div><div class='line' id='LC6'><span class="w">     </span><span class="o">~@</span><span class="nv">body</span><span class="w"></span></div><div class='line' id='LC7'><span class="w">     </span><span class="p">))</span><span class="w"></span></div><div class='line' id='LC8'><br/></div><div class='line' id='LC9'><span class="p">(</span><span class="nf">defn-</span><span class="w"> </span><span class="nv">exec-cmd</span><span class="w"> </span><span class="p">[</span><span class="nv">cmd</span><span class="w"> </span><span class="nv">context</span><span class="p">]</span><span class="w"></span></div><div class='line' id='LC10'><span class="w">  </span><span class="p">(</span><span class="nf">merge</span><span class="w"> </span><span class="nv">context</span><span class="w"> </span><span class="p">(</span><span class="nf">cmd</span><span class="w"> </span><span class="nv">context</span><span class="p">)))</span><span class="w"></span></div><div class='line' id='LC11'><br/></div><div class='line' id='LC12'><span class="p">(</span><span class="nf">defn</span><span class="w"> </span><span class="nv">exec-chain</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="w"> </span><span class="nv">cmds</span><span class="p">]</span><span class="w"></span></div><div class='line' id='LC13'><span class="w">    </span><span class="p">(</span><span class="nf">loop</span><span class="w"> </span><span class="p">[</span><span class="nv">chain</span><span class="w"> </span><span class="nv">cmds</span><span class="w"></span></div><div class='line' id='LC14'><span class="w">           </span><span class="nv">ctx</span><span class="w"> </span><span class="p">{}]</span><span class="w"></span></div><div class='line' id='LC15'><span class="w">      </span><span class="p">(</span><span class="nf">if</span><span class="w"> </span><span class="p">(</span><span class="nf">first</span><span class="w"> </span><span class="nv">chain</span><span class="p">)</span><span class="w"></span></div><div class='line' id='LC16'><span class="w">        </span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="p">(</span><span class="nf">rest</span><span class="w"> </span><span class="nv">chain</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">exec-cmd</span><span class="w"> </span><span class="p">(</span><span class="nf">first</span><span class="w"> </span><span class="nv">chain</span><span class="p">)</span><span class="w"> </span><span class="nv">ctx</span><span class="p">)))))</span><span class="w"></span></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/9e843e7725b6a18594ae/64f0a6391ddf51de0a5e9b0297f97eee1e735ef2/gistfile1.clj" style="float:right;">view raw</a> <a href="https://gist.github.com/9e843e7725b6a18594ae#file_gistfile1.clj" style="float:right;margin-right:10px;color:#666">gistfile1.clj</a> <a href="https://gist.github.com/9e843e7725b6a18594ae">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>The above can now be utilized with the following api&#8230;</p><div id="gist-645730" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="p">(</span><span class="nf">exec-chain</span><span class="w"> </span></div><div class='line' id='LC2'><span class="w">  </span><span class="p">(</span><span class="nf">make-cmd</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">(</span><span class="nf">println</span><span class="w"> </span><span class="s">&quot;Executing first&quot;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="no">:first</span><span class="w"> </span><span class="s">&quot;first arg&quot;</span><span class="p">})</span><span class="w"></span></div><div class='line' id='LC3'><span class="w">  </span><span class="p">(</span><span class="nf">make-cmd</span><span class="w"> </span><span class="p">[</span><span class="nv">first</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nf">println</span><span class="w"> </span><span class="s">&quot;Executing second:&quot;</span><span class="w"> </span><span class="nv">first</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="no">:second</span><span class="w"> </span><span class="s">&quot;second arg&quot;</span><span class="w"> </span><span class="no">:random</span><span class="w"> </span><span class="s">&quot;random arg&quot;</span><span class="p">})</span><span class="w"></span></div><div class='line' id='LC4'><span class="w">  </span><span class="p">(</span><span class="nf">make-cmd</span><span class="w"> </span><span class="p">[</span><span class="nv">second</span><span class="w"> </span><span class="nv">random</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nf">println</span><span class="w"> </span><span class="s">&quot;Executing third:&quot;</span><span class="w"> </span><span class="nv">second</span><span class="w"> </span><span class="nv">random</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="no">:third</span><span class="w"> </span><span class="s">&quot;third arg&quot;</span><span class="p">}))</span><span class="w"></span></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/77589bab1220c6f528b0/612c33c3b552945a6e65496eff1e2135500e1bc0/gistfile1.clj" style="float:right;">view raw</a> <a href="https://gist.github.com/77589bab1220c6f528b0#file_gistfile1.clj" style="float:right;margin-right:10px;color:#666">gistfile1.clj</a> <a href="https://gist.github.com/77589bab1220c6f528b0">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>Yielding (in SLIME REPL):</p><p><pre>
Executing first
Executing second: first arg
Executing third: second arg random-arg
nil
</pre></p><p>Running a similar script with an added parameter in the third command that doesn&#8217;t exist in the chain</p><div id="gist-645737" class="gist"><div class="gist-file"><div class="gist-data gist-syntax"><div class="highlight"><pre><div class='line' id='LC1'><span class="p">(</span><span class="nf">exec-chain</span><span class="w"> </span></div><div class='line' id='LC2'><span class="w">    </span><span class="p">(</span><span class="nf">make-cmd</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">(</span><span class="nf">println</span><span class="w"> </span><span class="s">&quot;Executing first&quot;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="no">:first</span><span class="w"> </span><span class="s">&quot;first arg&quot;</span><span class="p">})</span><span class="w"></span></div><div class='line' id='LC3'><span class="w">    </span><span class="p">(</span><span class="nf">make-cmd</span><span class="w"> </span><span class="p">[</span><span class="nv">first</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nf">println</span><span class="w"> </span><span class="s">&quot;Executing second:&quot;</span><span class="w"> </span><span class="nv">first</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="no">:second</span><span class="w"> </span><span class="s">&quot;second arg&quot;</span><span class="w"> </span><span class="no">:random</span><span class="w"> </span><span class="s">&quot;random arg&quot;</span><span class="p">})</span><span class="w"></span></div><div class='line' id='LC4'><span class="w">    </span><span class="p">(</span><span class="nf">make-cmd</span><span class="w"> </span><span class="p">[</span><span class="nv">second</span><span class="w"> </span><span class="nv">random</span><span class="w"> </span><span class="nv">does-not-exist</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nf">println</span><span class="w"> </span><span class="s">&quot;Executing third:&quot;</span><span class="w"> </span><span class="nv">second</span><span class="w"> </span><span class="nv">random</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="no">:third</span><span class="w"> </span><span class="s">&quot;third arg&quot;</span><span class="p">}))</span><span class="w"></span></div></pre></div></div><div class="gist-meta"> <a href="https://gist.github.com/raw/4b9ad44e53e8c5ad73aa/17756d40b013c13a84074e54ced3e34af9178448/gistfile1.clj" style="float:right;">view raw</a> <a href="https://gist.github.com/4b9ad44e53e8c5ad73aa#file_gistfile1.clj" style="float:right;margin-right:10px;color:#666">gistfile1.clj</a> <a href="https://gist.github.com/4b9ad44e53e8c5ad73aa">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.</div></div></div><p>Throws an exception (in SLIME REPL):</p><p><pre>
'does-not-exist' argument is required!
  [Thrown class java.lang.Exception]
</pre></p><p>Of course the above can be much improved, one off the top of my head improvement is to allow default values for arguments that don&#8217;t exist and possibly be able to specify arguments who&#8217;s lack of should throw and exception an in other cases either bind a nil or default value.  But the concise example demonstrates similar abilities of my java program but with added runtime argument name matching.  I&#8217;d love to see if the same can be accomplished with a statically typed language with type compile time vs. runtime argument checking.  Going to investigate this with Haskell and Scala this week.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2010/10/state-machine-with-clojure-macros-and-runtime-argument-inference.html/feed</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>On JVM, languages, platforms, and frameworks</title><link>http://ilyasterin.com/blog/2010/10/on-jvm-languages-platforms-and-frameworks.html</link> <comments>http://ilyasterin.com/blog/2010/10/on-jvm-languages-platforms-and-frameworks.html#comments</comments> <pubDate>Fri, 22 Oct 2010 00:01:26 +0000</pubDate> <dc:creator>Ilya Sterin</dc:creator> <category><![CDATA[Uncategorized]]></category> <category><![CDATA[clojure]]></category> <category><![CDATA[Java]]></category> <category><![CDATA[jvm]]></category> <category><![CDATA[scala]]></category><guid isPermaLink="false">http://ilyasterin.com/?p=314</guid> <description><![CDATA[Today apple announced through their Java update that their support for the JVM is now deprecated and will possibly be removed from the future OS releases. The blogosphere is flaming, mostly with Java supporters who are either pissed off at Apple, worried about the future of their investment in the Java platform, or both. I [...]]]></description> <content:encoded><![CDATA[<p>Today apple announced through their Java update that their support for the JVM is now deprecated and will possibly be removed from the future OS releases.  The blogosphere is flaming, mostly with Java supporters who are either pissed off at Apple, worried about the future of their investment in the Java platform, or both.  I don&#8217;t think the future of the Java platform should be in question due to any apple decisions, at the end of the day, there aren&#8217;t many production Java deployments on OS X, but it is a fact that a large portion of Java developers utilize OS X as their primary development platform.  These developers, without proper support for their environments, will move to Linux and maybe even Windows.  This move alone will probably not hurt apple in the short run, but their behavior towards isolating different developer groups, will eventually come back on them.  Developers from any environments will cautiously approach, as the tamed Leopard and eventually Lion might bite them in the ass at the least expected moment.</p><p>It might be that Apple wants Oracle to take the charge in maintaining the OS X port and deprecating support might be a way to negotiate this without face-to-face negotiations.  I&#8217;m fine with that, frankly I could care less who provides the JVM, as long as one is provided and is relatively actively supported.  Until that announcement happens, this is yet another bump in the future of the JVM.  First the Oracle purchase of Sun, then the lawsuit, and now the decision by Apple, definitely creates unneeded distractions for this platform&#8217;s developers all over the globe.</p><p>So I started this not to gripe any more about Apple&#8217;s decision, I&#8217;m sure there are enough posts out there flooding your RSS streams to keep you busy, rather I wanted to question the future of languages/industry in regards to the language/platform of the future.</p><p>Last week I attended the <a href="http://strangeloop2010.com/">StrangeLoop conference in St. Louis</a>.  It was a gem of a conference, definitely the best I&#8217;ve been too in a long time.  Alex, besides seeming like an overall awesome guy, has some extraordinary &#8220;brilliant people herding&#8221; abilities.  How he managed to bring together a group of brilliant speakers and then convince another group of awesome developers to attend, is beyond me.  The conference had some great talks and panels about the latest/greatest and bleeding edge tech stuff.  One of the best panels was about the future of programming languages.  The panel consisted of (Guy Steele, Alex Payne, Josh Bloch, Bruce Tate, and Douglas Crockford), all whom I have great respect for.  One prevailing factor in most discussions in this panel as well as throughout the conference, has been concurrency.  In the mutli-core/cpu world, what language/platform will allow for this paradigm transition to happen seamlessly.  The fact is that although there are some awesome innovations/implementations going on in this area, STM, Actors, fork/join, and various others, none have yet abstracted the concurrency model away from the developer, as seamless as memory management and garbage collection is done in today&#8217;s runtime environments.  But this is an exciting time to be in, many ideas are flowing around and something will appear on the horizon sooner or later.  This something, as Guy Steele pointed out, will most likely be a model that will allow for divide/conquer, map/reduce operations to happen through language idioms and possible seamless abstractions.  Accumulators are evil <img src='http://ilyasterin.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /></p><p>There are many languages/platforms out there today, but none have been as predominant and as overall polished as Java and the JVM.  From the language perspective Java&#8217;s getting stagnant and to some, boring, but the fact that it has an ecosystem of wonderful libraries and products is hard to ignore.  The fact that all of these are bytecode compatible is even more to rant about, as with the advent of numerous great languages built on top of the JVM, it makes the transition to a different language and programming paradigm, much easier.  It is truly hard to think of any current platform/VM that&#8217;s more prevalent and better suited for large scale enterprise development than the JVM.  .NET comes to mind, but I doubt anyone from the non-Microsoft camp will be switching <img src='http://ilyasterin.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .  There are other platforms, most notably Python and Ruby, but although both are credible, the presence of GIL on both, make the choice of using them in a concurrency model very difficult.  You can architect and deploy your system as multi-process vs. multi-thread and arguably that model has its benefits, mostly by getting rid of the shared state model concurrency issues, but we (at least I do) like to have a choice.  This decision shouldn&#8217;t be shoved down our throats because the language development camp doesn&#8217;t want, doesn&#8217;t think one is necessary, or [add your own excuse here] to produce a thread-safe non-GIL thread model.</p><p>The other issue with most of these languages/platforms, as well as the other ones I like, is the deployment options.  They suck!  From providing modular builds to deploying production applications, they just aren&#8217;t as polished and in most cases as stable/supported as the JVM ones.  Common Lisp, one of my favorites as of late, for example, is an awesome language with numerous compilers/interpreters.  Lisp doesn&#8217;t have a good packaging, dependency resolution, and build story, but even if you can get past that with some of the available half-baked solutions, then when it&#8217;s time to build/compile/deploy your app, you&#8217;re fucked, unless you want to build one yourself.  I enjoy such challenges on Friday/Saturday nights, but not when time is limited and milestones are due (which is most of the time).</p><p>Ruby and Python for example, have a decent package managers gem and easy&#95;install/pip respectively, but two problems lurk.  First, lots of modules are written in C and in many cases, in my experience, are a big pain in the ass to compile, especially with today&#8217;s heterogeneous architectures i386, x86_64, etc&#8230;  Lots of incompatibilities arise, forcing more time away from doing what I should be doing.  Somehow my milestones never include the 2+ day derailments due to such issues.  Maybe that&#8217;s what&#8217;s left of my optimism.  The second problem only applies if you&#8217;re writing a web app and if you are, then you know the issues.  Where are those stable/supported app servers?  WSGI and rack should provide answers soon, for now, there are many options and none are without major issues as well.  Some are a pain to install/deploy, some aren&#8217;t actively maintained.  I mean, am I just being anal and asking for way too much or am I eternally spoiled by the JVM.  Is it too much to ask to bundle the application into some archive or directory structure and just drop it in somewhere or point your server config towards it.  Either way, even if they ease the pain of deploying webapps, the fact that [Python/Ruby] are not suitable in multi-core/cpu environments where threads are needed, is a show stopper for lots of apps I write.  I know I can architect around the issues, but again, why should I have to program to the platform vs. the other way around.  Give me the choices and trust me to make the best decision.</p><p>The next things is native GUI development.  It is true that lots of interesting apps today are developed and deployed as web apps, but that doesn&#8217;t discount the fact that there is still a need for a native GUI in lots of use cases.  Swing provides a good and in some instances really good, cross platform GUI library which allows to deploy your GUI across most popular platforms with 95% or more cross platform consistency.  That sounds pretty good to me.</p><p>There are other toolkits, wxWidgets, QT, etc&#8230;, which also have bindings to python and ruby, but again, with today&#8217;s multicore, it would be a shame to not be able to utilize these cores simultaneously due to GIL.  The bindings in languages that due provide a better concurrency story, work great, but these languages still suffer from the other pain points I mentioned before (i.e. deployment, build, package management, etc&#8230;).  It&#8217;s a Catch-22.</p><p>So maybe I&#8217;m missing something here, but I think the JVM is the best option we have at this time that allows for multiple platforms, languages, paradigms, and comes with a great success story in the enterprise (build tools, deployment/modularity, enterprise grade servers, etc&#8230;).  Languages implemented on top of the JVM benefit from this quite successful ecosystem.  Ah, and might I mention that great libraries exist for about anything you&#8217;re trying to do.  This is also true of Python, but I can&#8217;t say the same for Ruby.  Ruby has numerous gems for most tasks, but they all seem half-baked at most.  There are frameworks like Rails and Sinatra, which are great and fully supported with active communities, though as long as you don&#8217;t venture too far off the traditional path.</p><p>JVM has it&#8217;s own set of issue, the fact that it was written with static languages in mind and lacks support for dynamic bindings, tail call optimizations, and other things that make writing languages on top of it more difficult.  It&#8217;s future is now also in question due to the new Oracle stewardship and the legal obstacles it chose to pursue rather than spend that time and money on the platform.  Nevertheless, the ecosystem is still flourishing, kept afloat but tons of great developers and supporting companies who care about the platform and greatly benefit from it.  JVM allows us to program in different languages while being concentrated on the task at hand, not peripheral issues like compiling for different architectures, battling the deployment inadequacies, not being able to utilize cores efficiently, and a variety of other issues.  JVM ecosystem might not have the most ideal solutions to these problems, but they are far better than anything out there right now.   If people that spend their time bashing the JVM platform would spend as much time making their platform better, maybe we&#8217;d have other choices.</p><p>I&#8217;d love to hear other&#8217;s thoughts on this topic.  What do you think about the JVM and what&#8217;s your language/platform of choice.  How do you build, deploy, distribute your applications?  What concurrency options are available on that platform and how they compare to others?  I&#8217;m familiar with most JVM options, especially Clojure and Scala, so I&#8217;m mostly asking for anything outside of the JVM ecosystem.  I hope to someday compile a list of these and present them in an objective manner, for now, all I have is my empirical opinions.</p> ]]></content:encoded> <wfw:commentRss>http://ilyasterin.com/blog/2010/10/on-jvm-languages-platforms-and-frameworks.html/feed</wfw:commentRss> <slash:comments>6</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using memcached

Served from: ilyasterin.com @ 2012-02-05 22:57:08 -->
