memamsa http://blog.memamsa.com ideas & investigations posterous.com Sat, 04 Dec 2010 21:21:15 -0800 Keeping Rails Migrations Rolling http://blog.memamsa.com/keeping-rails-migrations-rolling http://blog.memamsa.com/keeping-rails-migrations-rolling
Migrations allow Rails developers to easily incorporate schema changes as they develop and enhance their web application or service. Rails comes with a set of default rake tasks for migrations, which look for and load a set of time-stamp ordered files. By convention, these file names map to a set of class names, and on these, the migrator invokes the "up" or "down" class method as appropriate. 

The migration is thus ruby code, and lets the developer be very flexible in adjusting the schema and adjusting existing database information based on evolving requirements. For non-trivial applications, it is common to have many hundreds of migrations, added over time by different developers. 

Migrating Cleanly

As a general guideline, a new developer or a developer cloning the app on a new machine should always be able to migrate cleanly. Thus, either of the two below should work without a hitch.

rake db:drop; rake db:create; rake db:migrate;
rake db:reset

The latter has the same effect as the former, except that db:reset applies the pre-existing schema.rb while the former loads and runs all the migrations individually, creating a new schema.rb file. 

In my experience there are some creeping code and environment problems which can break migrations, especially for those that come after you to work on the project. Here is a list of common mistakes or gotchas and how to avoid them to keep your migrations rolling:

0) Ignoring db/schema.rb from source control 

In many projects, db/schema.rb is kept out of the source repository. The rationale is that it can always be recreated by running migrations. The perceived danger is if someone down-migrates for testing, and then checks in the stale schema.rb. However, this is less of a worry, since you are trusting your developers to have better sense and run the latest unit tests before committing. (You do have tests, right?!) 

The advantage of having a schema.rb is that a new developer can quickly view the database schema, and just run db:reset to get started. 

1) Assumptions about the DB and existing columns 

This is most likely in the case of projects that deal with a pre-existing database, and migrations start from the point where Rails was used to enhance the product with new features or a semi-independent sub-system. This bifurcates schema knowledge needlessly. 

When dealing with legacy databases, you should take the time to use rake db:schema:dump or some manual process to create a 00001_initial_db_schema.rb. You will thank yourself you took an afternoon out to do it. 

You should also use rescues judiciously to deal with legacy databases, especially if there are multiple copies which may have drifted from each other (e.g. no indexes on staging/test legacy server) over time.

2) Migrations used to populate data. 

Yes, migrations can have any Ruby code, and it is possible to include some nifty programmatic ways to pre-populate admin users, basic settings and other fun stuff. 

But migrations is not the place for it. Instead seed data using db/seed.rb and run rake db:seed. Consider gems such as populator, or create rake tasks for common or periodically imported data. Some apps might have an admin interface which can be used for introducing necessary data. 

3) Using Model functionality in migrations 

Models are most commonly used in migrations to "fix-up" data when modifying column semantics or changing table relationships. This is necessary, and allowed. In fact, Rails even provides the #reset_column_information method on ActiveRecord models to reflect the latest migration. 

Models can introduce circular or irreconcilable dependencies amongst your migrations, especially in conjunction with other mistakes.  

Let's say you add a column to the database in a later migration. You change the model with a corresponding validation on that field. You might still be able to run all migrations, unless you are creating dummy model objects. Or if you are doing fixups which involve saves or updates. Or more commonly, if you renamed fields, and therefore the corresponding validations on the renamed fields don't work on migrations preceding the renaming. 

You mitigate this either by using SQL statements with "execute" in the case of data fixups, or by using stripped down "mock-models" as nested classes inside your migration. 

4) Using ActiveRecord models in environment.rb, or in initializers

It might be tempting to use your nifty model (e.g. Setting, Tag) or some such as part of environment, configurtation or initialization. Terrible mistake, and usually indicative of teams which never run tests, continuous integration or other deployment mechanisms. Why? Because the Rails environment is initialized not just by the app server, but also by rake tasks, including migrations. Any model used in initializers means that migrations on an empty database can never run. 

5) Renaming database tables

If you have to rename database tables, you might want to ensure that you are not using any models (with the old name) in your earlier migrations. If you are, and have to rename, consider 3) above. Or you might want to consolidate earlier migrations and do some cleanups. 

6) Inserting migrations or adjusting order

Sometimes, you need to insert a migration other than at the end. Other times, you may want to ensure certain migrations are always run last. For older Rails projects, you might have migration files with simple numerical order, e.g. 022_migration_name.rb. Newer migrations would have a time-stamp. 

Be consistent with migration numerals, especially the number of digits (e.g. 0001_early_fixup, or 9999_must_be_last_migration).  If using timestamps, create a timestamp pattern that stands out and is used consistently to indicate a fix-up. (e.g. ending in 99 or 77)

7) Dividing migrations into multiple directories. 

Ideally, all migrations should be in the db/migrate directory. A well-written plugin or gem would have generate scripts for including its required schema into the application. If your app was componentized and those modules developed in parallel, consider re-syncing schema by adding and checkpointing new migrations. 

8) Short-circuiting old or unused migrations

Let's say a particular migration is no longer necessary or required. Take the time to delete it, including other dependent migrations. Don't just "return" or - even worse - raise "Error" from migrations you don't want. This introduces cognitive and processing overload for a new developer, while possibly hiding bugs. 

By taking these steps and avoiding the mistakes above, you can enjoy all the benefits of Rails migrations and make life easier for you, your team and future contributors.  

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Fri, 01 Oct 2010 08:51:00 -0700 Rogue Viruses - With Robot Armies http://blog.memamsa.com/rogue-viruses-with-robot-armies http://blog.memamsa.com/rogue-viruses-with-robot-armies
Media_httpwwwfsecurec_siaip

"It could adjust motors, conveyor belts, pumps. It could stop a factory. With right modifications, it could cause things to explode."

Stuxnet exploits vulnerabilities in Windows PCs to make a home and spread itself. But it does not stop there. It is looking for Siemens micro-controllers that run industrial systems. So it can do some thing.

Cheaper and easier than sending the Mission Impossible team.

http://www.f-secure.com/weblog/archives/00002040.html

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Fri, 23 Jul 2010 15:27:49 -0700 Hello Posterous! http://blog.memamsa.com/hello-posterous http://blog.memamsa.com/hello-posterous We took advantage of the Wordpress importer to migrate this blog. Not quite the same as flipping a switch, but overall, quite painless.

Definitely worthwhile, with one less moving part to worry about in our infrastructure. And awesome features like post by email.

Sent from my iPhone

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Fri, 09 Jul 2010 07:45:39 -0700 Mixing in MongoDB http://blog.memamsa.com/2010/07/09/mixing-in-mongodb http://blog.memamsa.com/2010/07/09/mixing-in-mongodb I have started using MongoDB for specific use cases in production. I don't see the world in black and white, and neither should you. My goal in writing this post is to note down the rationale and list some gotchas when using it with MongoMapper.

Media_httpapimongodbo_qeoqq
Media_httpstaticrails_kiccp

MongoDB provides document-oriented storage, with replication, indexing and rich query support. It blends aspects of distributed key-value stores by keeping most of the data in memory, pulls in fine-grained indexing and query language reminiscent of relational databases, provides map-reduce support for data processing similar to Big Table, while optimizing for fast in-place modifications. In the near term, it will provide horizontal scaling and sharding.

The tradeoff for MongoDB is in lack of transactions and being not fully ACID.  This means MongoDB does not offer single-server durability. Data is only eventually consistent. Due to filesystem operational choices (fsync vs. append-only writes, commit log, etc.) MongoDB can lose data during hard server loss.

Realizing all theses aspects, why did I choose to go with MongoDB? The Problem

I want to track a bunch of data for certain kinds of views and then display custom analytics. The data collected includes a combination of request environment and internal statistics correlated with request parameters.  I did not want to write this to a traditional database for every request because a) the data is adjunct to the functionality, b) it involves a select+insert or select+update for each request and c) writes are expensive. Furthermore, the write is not critical enough to hold up the request, and definitely not worth adding a queue infrastructure.

Initially, I wrote a batch-mode logfile analyzer which periodically collates this information into a traditional database. It worked great, except it was not real-time, and every time I needed to track a new statistic I had to run a migration. As the app moved to a clustered environment, some of the data was in the front-end logfiles, and some in the app slices. Running different kinds of batch jobs on multiple servers was getting clunky.

I looked at several alternatives, and quickly eliminated most as not being a good fit for the problem, or sometimes for irrational reasons.

  1. Redis - Persistence seems awkward and schema support is limited.
  2. CouchDB - Requires reading up on map-reduce and ability to make views before you can use it.
  3. Cassandra - Requires mucking with Java VM installs, XML configurations and jar files and grok the Thrift interface.
  4. HBase , Voldemort, others - Great, and worth a look someday. But...
At some point, in going down the list, I hit on mongoDB and came across the wealth of documentation and support base that 10gen has created. As a Rubyist, I found in MongoMapper a good balance of ActiveRecord goodness and the MongoDB API characteristics. I also love the MongoDB API, because it is similar to a Javascript-style database API that I wrote for airdb. MongoDB also provides support for map/reduce operations, so you can use it for aggregate data processing when you need it. Several others have documented their switch to MongoDB, and there was a strong alignment in the usage case, whether for logging, analytics or dealing with high volume, aggregate data - where the loss of a few hundred writes out of millions is not a big deal. Finally, one aspect that sealed the choice was the notion of modifier operations, which allow fast, atomic, in-place incrementing of counters, something that I need to do 99% of the time for this problem. Installing MongoDB with Ruby and MongoMapper was straightforward.  There are good instructions for using it with Rails. I am not doing a complete switch, just mixing it in. The easiest way to do that, I found was to add the mongo configuration to database.yml.
production:
  adapter: mysql
  host: m03
  database: myapp_production
  mongo_database: myapp_production
  mongo_host: m04
And then read in and set the MongoMapper.connection and MongoMapper.database using this information in config/initializer/mongo_connect.rb
dbconf = YAML::load(File.read("#{RAILS_ROOT}/config/database.yml"))
mongo_db = dbconf[Rails.env] ? dbconf[Rails.env]['mongo_database'] : false

if mongo_db
  mongo_host = dbconf[Rails.env]['mongo_host']
  $stderr.puts "MongoDB connecting to #{mongo_db} on #{mongo_host}"
  MongoMapper.connection = Mongo::Connection.new(mongo_host)
  MongoMapper.database = mongo_db
end
Don't forget to add the per-worker process configuration to your initializer config if you are using Passenger Phusion. Some other gotchas:
  1. Line up your mongo_mapper, bson and bson_ext gems so they are in sync. One symptom of mismatch are non-obvious error messages such as not finding OrderedHash.
  2. If you use Array data fields, then MongoMapper will create and populate the Array field on #create, but only if you provide a lambda default.
  3. If you want to do upserts, you must drop down to the Mongo Ruby Driver. Fortunately doing this is as easy as invoking methods on the MongoMappedClass#collection method.
  4. If your sole use-case is to do upserts, avoid Array fields. It is not possible to access a single Array field element using positional or dot-notation when doing upserts.
In sum, you can start using MongoDB alongside MySQL inside your Rails projects as appropriate and side-step the whole SQL vs. NoSQL wars. Here is to humongous fun while data processing.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Sun, 04 Jul 2010 06:13:00 -0700 Twilio on Rails http://blog.memamsa.com/2010/07/03/twilio-on-rails http://blog.memamsa.com/2010/07/03/twilio-on-rails

A few weeks ago, I looked up Twilio in conjunction with a telephony project. I was intrigued by the promise of a simple REST web API for building SMS and voice based interactions within web apps. In prototyping, I ended up developing a Rails plugin called Twilioflow which allows simplified development and testing of telephony apps.

Having spent some time at AT&T/Lucent Bell Labs, I had heard my share of war stories from the programmers and managers who worked on the venerable Audix system. From that perspective, Twilio is yet another example of creative destruction made possible by improvements in the general purpose computing platform coupled with an extensible network protocol (HTTP). Operationally, Twilio goes even further by harnessing Amazon's EC2 infrastructure and we can be sure they have numerous other tricks up their sleeve. In short, for web apps, the Twilio server acts like a well-behaved browser client, supporting cookies and redirects, and providing call control parameters mimicking form submissions. I started prototyping based off their examples, but soon ran into style as well as design issues. Its fine to have Ruby/Rails examples which follow the PHP form, but special purpose controller methods containing repetitive if-then-else code redirecting to other special purpose controller methods is quite far from being DRY or RESTful or testable when it comes to building a decent Rails app. In developing an alternative approach, I applied these guiding principles:

  1. For an interactive voice response application, the phone tree really represents the application's business logic and should be as much in the model as possible.
  2. The phone tree has the potential to grow large and complicated. Thankfully, Ruby allows us to quickly and cleanly write DSLs.
  3. In general, the controller pattern is basically an accept-process-respond based on Twilio request parameters, particularly Digits.

The phone tree is really a graph and can be represented as a FSM. I looked around and found the excellent Workflow library, which provides a great and intuitive way for specifying state machines and event transitions. Using additional IVR specifiers the phone tree can be contained within the model class allowing it to be unit-tested independently. Here is an excerpt of on particular Interaction model, inspired by Twilio's Hello Monkey examples.

class Interaction < ActiveRecord::Base   include Workflow     workflow do      state :hello do        say "Gorillas. Wasssaaap!"        prompt 1, "If you are a jungle-dweller, press 1", :primal, :go => :jungle_dweller        prompt 2, "Captured primates, please press 2", :captured, :go => :zoo_habitant        prompt 9, "To end this call, press 9", :end_call, :go => :goodbye     end     #.... Other states and model methods ...   end end

There are many more aspects about the IVR DSL outlined in a detailed example, such as dynamic key press options, multiple digit handling, response decisions and more. The goal is to make it easy to build real-world personalized phone menus integrated with databases or other web services. The controller response is an encoding of the current interaction state. So, the twilio request handler can provide a simplified generic response such as this one:

keys = @interaction.accepts numDigits = (keys and not keys['#']) ? "1" : "" xml.instruct! xml.Response do   @interaction.says.each do |sentence|     xml.Say(sentence, :voice => 'woman', :language => current_locale.to_s)   end   if not keys.blank?     xml.Gather :action => action, :method => "POST",  :numDigits => numDigits do     end   end end

Finally, it is possible to package all this functionality as a Rails plugin (or a gem). Adding a Twilio interaction to a web app can then be jump-started as follows:

$ ruby script/generate twilio interaction

In addition to stand-alone unit testing of your models, you can also easily test the interactions in your development environment from within the browser. Functional testing with rake is also enabled. Twilioflow is available on github for your use and improvements.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Sat, 29 May 2010 20:16:00 -0700 Rebalancing and Culling http://blog.memamsa.com/2010/05/29/rebalancing-and-culling http://blog.memamsa.com/2010/05/29/rebalancing-and-culling

Two years ago, over the summer, I put out several social games on Facebook, Hi5 and Orkut.

It was fun to brainstorm ideas, get something out, and watch the rush of users hitting your servers. The whole process of maintaining, updating and expanding your apps and increasing user engagement was instructive. Another bonus was understanding the intricacies of building on top of other platforms and the headaches of dealing with ever-changing API and policies.  In short, it was a great experience.

Experience is what you get, when you didn't get what you wanted. That's absolutely true.

We didn't get millions of users, only thousands. Our ad revenues never went beyond a monthly coffee or two. But it instilled in us the discipline for designing features, writing code and shipping it, all while managing deployments, monitoring servers, optimizing response times, and the whole end-to-end, full-stack thinking inherent in successful web app and services.

Over time, though, it becomes necessary to rethink, reassess and let go. This is as certain (and perhaps more important) for software, as it is for physical items or other assets. While the space and resource cost for software - in terms of bandwidth, storage or other rents - is negligible and easily amortized over other activities, the mind-space requirements are costly, and get more expensive over time.

In addition to your own code complexity, you also have to deal with changes in underlying libraries. Some, such as OpenSocial and Google are good at API versioning and stability. Others change API, break functionality or undermine app features through policy changes, requiring continual investment.

As an investor in code, I am rebalancing my portfolio. As an app maker, I am culling my stock of apps. I am delisting the apps from the respective directories, and putting in a notice that they are going to go away. Soon, they will be gone.

Happily, modern web apps, especially third party apps that live on other sites and platforms, are impossible to mothball. I will perhaps keep a few screenshots to remind myself of all the design atrocities.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Tue, 18 May 2010 20:21:56 -0700 AirDB can has_many_through http://blog.memamsa.com/airdb-can-hasmanythrough http://blog.memamsa.com/airdb-can-hasmanythrough We now have a better, declarative and richer mechanism of specifying model relationships. In the process, AirDB now has support for has_many_through associations. As discussed earlier for join table attributes, the cleanest way to express the association is a has_many_through, where two models have a many to many relationship through an intermediate model. Join table attributes are a nice hack for someone who does not want to rewrite their application code to introduce the intermediate Model class. In some cases, such as self-referential many-many associations, or when you are in the early stages of designing the schema and the application, you may find it appealing to manage the join table as a first-class Model. If so, then has_many_through will help you. Here is a pattern that is now enabled easily by the new code. A Person is friends with many other People. They in turn are friends with other People. Friendship is directed, that is, A might think B is a friend, but B might not consider A as friend. In doing this, it was easy to apply a simplified version of the Migrator mechanism using a new class called Relater. For our example, we will have two models, a Person and Relationship. Follow the links to see the full source code on github. The key thing that enables this is the new declarative style of specifying associations and their options.
public dynamic class Person extends Modeler {
     private static const relations:Relater = new Relater(Person,
          function(me:Relater):void {
              me.hasMany('friendships', {
                    foreign_key: 'from_id',
                    class_name: 'example.Relationship'
              });
              me.hasMany('friends', {
                    through: 'friendships',
                    foreign_key: 'to_id',
                    class_name: 'example.Person'
              });
         });
       // migrations and other class code follows
   }
}
An added benefit of using this association mechanism is you don't have to remember setting external compiler properties. The association look-up is faster as it involves a single access on a prototype member, as opposed to fetching and iterating through class meta-data. Internally, the new Relater seamlessly maintains the various Associators for Modeler objects, and allows backward compatibility. So the old style meta-data based declarations in existing code will still work. Have fun and make many associations through AirDB!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Thu, 08 Apr 2010 19:21:00 -0700 iAd - Applevertising http://blog.memamsa.com/iad-applevertising http://blog.memamsa.com/iad-applevertising
[[posterous-content:xz2yfDkeiBbMS3g3RZuB]]

As expected, Apple CEO Steve Jobs announced the iAd Mobile Advertising platform from Apple. Apple wants to enable highly interactive and emotional advertising on iPhones. 

According to Jobs, unlike the desktop, "where search is everything", on the iPhone, everyone is interacting with apps. And there is an app for everything, with tons of developers making them free. So if developers have to use advertising to make money, Apple wants to ensure that the ads also benefit from the famous Apple design sensibility.

There are several technical and economic aspects of the iAd platform, and their implications on overall web advertising, that we will see in the weeks and months to follow. But, Apple's approach is an indication of two key aspects: 

  1. People want free stuff, developers give it to them, look to advertising to make money. 
  2. Advertising is being redesigned for new interaction and engagement modalities. 

Shiny and exciting times ahead.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Wed, 07 Apr 2010 20:49:00 -0700 Bootstrapping Stories - TiE Panel 2 http://blog.memamsa.com/2010/04/07/bootstrapping-stories-tie-panel-2 http://blog.memamsa.com/2010/04/07/bootstrapping-stories-tie-panel-2

Within just 3 months into the new year, the TiE Oregon SW & Internet group has organized two great events for entrepreneurs, gathering together six successful veterans who shared their stories, recounted lessons learned, mistakes made and the opportunities taken. Both events were packed with an engaged audience, resulting in informative and honest Q&A.

 

Sudhir BhagwanMatt ComptonRyan BuchananTaizoon DoctorNitin Khanna

 

The first event in February featured Nitin Khanna, former Chairman and CEO of Saber Corp, Sudhir Bhagwan, former Chairman and CEO of SnapNames and Matthew Compton, then venture partner at Madrona and now CEO at ShopIgniter. That discussion was about getting big and growing fast with venture capital, and was covered by the Oregon Business magazine. The second event held yesterday was focused on bootstrapping your startup into generating solid profits, and included Mona Westhaver, President of Inspiration Software, Taizoon Doctor, former CEO of Xovix and Ryan Buchanan, CEO of eROI. Both of these events were hosted by Brent Bullock at Perkins Cooie who did a splendid job of moderating and directing the flow of discussion, as well as elaborating on some of the legal aspects to issues faced by the panelists. Starting Out For those wondering about starting out, there were three diverse beginnings, each with a unique mindset.  As Ryan quipped, being naive can be a great strength, and he narrated how he quit his job in finance at Intel to start a dot-com technology company (in 2000), which went nowhere. Undaunted, he pitched in $1500 with a friend to license a software platform and offer email marketing services, which today has grown into a 50-person agency offering products of their own. Mona and her co-founder always considered moving from selling their time (as consultants) to selling products and building a company as a quest to make the most of their  skills and resources. She described their start 28 years ago, and the early setbacks - in terms of platform (CP/M supplanted by IBM-DOS) or partners (Radio Shack, which did not follow through on providing a channel for software vendors in their stores). Today, their visual learning and organizing software is a hit with educators and managers and Inspiration Software turns in strong profits. Taizoon saw in Xovix an opportunity to move beyond Intel managerial roles. As an earlier acquisition of Xircom, which the new owners at Intel wanted to sell, Taizoon stepped up to buy Xovix when a deal to spin it out to a private equity firm fell out at the last moment. With a hand-picked set of existing employees, Taizoon moved to Colorado, expanded the business with cash-flow, and sold it to Broadcom two years later. Formational Thinking So, what worked well, and what would they do differently in the early stages?

  • Cash is King. Focus on revenue right from the beginning, and get it as quickly as possible.
  • Set up roles and responsibilities with co-founders, and evaluate quarterly. If founders' interests diverge, make it easy to part ways by ensuring buy-sell agreements are in place.
  • Go with the cheapest entity that works for you. Incorporating in Oregon is fine for most early stage companies, and do not underestimate the pass-through advantages of S-corps. But do ensure that consulting agreements are proper and vetted.
  • Pick your partners and investors carefully. Always work to ensure you have options, because having no choice usually leads to worse outcomes.

Customers This is generally so obvious, that it needs repeating only to contrast it from venture-funded startups, where marketing and long term positioning can become more important than meeting day to day customer needs.

  • Know your customers, be where they are, go where they gather.
  • If you don't have a direct competitor, then perhaps there is no money there.
  • Start branding your offerings early, get your name out there.

Employee Hiring and Retention In contrast to venture funded startups, where options are a given aspect of employee compensation, bootstrapped companies tend to do better when giving out cash-only compensation at market rates. Of course, its hard to match large corporations in health care benefits, but if that can be included, you can get amazingly talented people who stick around with the company for a long time.

  • Pay employees before paying yourselves, and realize that as part of the founding team, you will likely be making less in salary than your key employees.
  • Help employees grow with the company, but also consider their personalities and choices. e.g. the CTO who wants to be more of a developer.
  • Profit-sharing can be a better motivator than stock options.

Taking Investment When it becomes necessary or beneficial to take on outside investment, it is better to take on investors who are aligned with your goals.

  • Would the investors prefer yearly dividends or would rather wait out for long term gains?
  • Carefully consider redemption rights, to provide the investors an exit opportunity, or give you the ability to buy them out on defined terms.

There is great advice and writings out there, but it cannot beat an opportunity to meet, ask questions and learn from other entrepreneurs. Several in the audience had specific questions, and there were some good after-the-panel discussions between attendees. Thanks to Mona, Taizoon and Ryan for sharing their stories and answering questions. Thanks also to Anu Khaira, Kanth Gopalpur and Brent Bullock who helped make this a great series of events.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Thu, 01 Apr 2010 05:16:00 -0700 iPad Strategy http://blog.memamsa.com/2010/03/31/ipad-strategy http://blog.memamsa.com/2010/03/31/ipad-strategy

Media_httpuploadwikim_mgopw
 

This weekend, tens of thousands will get their hands on the iPad. Several people have been playing with it already. John Doerr has been widely quoted with his lusty lines:

“I’ve touched it, I’ve carressed it and I hope to sleep with it this Saturday night. It’s not a big iPhone. It’s the future.”

That coupled with an announced doubling of the iFund has a lot of developers and companies considering iPad as a must-have checkbox platform and a potential moneymaker. So, when are you going to iPad enable your existing apps?  Alright, bring me a long enough lever, three super hackers and a warehouse full of Red Bull, and I, too, can move the world.

Media_httpuploadwikim_glbqf
Alas, reality bites. If history is any indication, there will be a Gold Rush II for iPad apps. This is a great opportunity for iPhone developers, agencies and related service providers. But, it also indicates that the iPad app store will quickly be saturated with thousands of me-too apps, or to be more accurate, me-too-iphone-apps-squared. So, if you are looking at the iPad as a new marketing channel, then you are going to be disappointed. On the other hand, if you have really innovative ideas that harness the full potential of the iPad, and more importantly, align with the user experiences that it is going to unleash, this is a great opportunity. This is what I think:

The tactile, gesture-driven, free to pass around iPad will be great for re-imagining board games and coffee table activities during family gatherings.

I have been asked, specifically, by clients and friends regarding iPad plans for mooifoto. The iPad can be a gorgeous (and expensive) photo display frame, and I am pretty sure it will come with a built in iPhoto version with great slideshow features. Apple loves to integrate with exactly one of each kind of leading external service,  so it will include Flickr and Facebook integration. Technically, getting mooifoto onto iPad is not going to be a straight port, since the iPad does not support Adobe technologies such as Flash or AIR. From a product perspective, my advice has been to own the family and close-t0-family niche by solving the pain points across multiple devices (e.g. iPhone, camera, computer) and sharing modalities that the bigger services ignore. So, to that end, the best approach would be to have a rich HTML5  UI built into mooifoto.com that plays with the novel (and as yet, only imagined) iPad experience. If you are a company providing an existing app or service, I would love to hear about your strategy for the iPad.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Sun, 31 Jan 2010 05:44:18 -0800 gClouds and iDevices http://blog.memamsa.com/gclouds-and-idevices http://blog.memamsa.com/gclouds-and-idevices The recent unveiling of the Apple iPad is portent for the evolution for Mac OS X towards the iPhone OS. Existing iPhone apps will run on the iPad, with presumably the same App Store model. Apple has also (carefully, purposely) not included Adobe Flash support for the iPhone and now the iPad. This implies that Apple is deadly serious about creating a third party developer ecosystem that is tied to its own SDK, licensing, runtime and payment mechanism. While Webkit and Safari remain at the forefront of web, HTML5 and Javascript support, given the evolution of Apple devices and custom interface gestures (e.g. pinch, expand, hold, etc.) as well as new revenue models through App Store downloads and in-app purchases, there is an emerging Dilemma for software developers and small companies to consider. Do you want to be in the cloud or on the device? Let me elaborate. Large companies rarely bet. They hedge. They will "continue to leverage their core website operations in creating and nurturing a viable consumer touchpoint through their iPhone applications strategy". But competent developers know that platforms and tools shape your thinking. When you live and breathe a world-view, you are more likely to be productive and create something worthwhile. Being in the cloud is hardly revolutionary, since everyone is already in the cloud, or talking about being in the cloud. We are talking about specializing in the cloud. Sure, there will be ways to deliver your service front-end to multiple devices using general purpose browser technology, but the winning devices will offer specialized experiences and you will not have the time or expertise to invest in them while defending yourself from Google-grabs and other pure-play cloud competitors. Today, making an iPhone app is a few weeks of work. Figure another two weeks for doing an Android version. But, the devices are going to be richer, there will be more bells and whistles and knobs on the platform, more hoops to jump through to get into the app stores, all the while thinking of more hooks to keep your users engaged. You might be able to do both, a rare possibility. A three-person-minimum company can emulate Apple - one guy doing the cloud part, another doing the device app, and the third channeling Jobs, exercising taste and overall control. Here is another thing to ponder about and wager on. In a future with separate cloud and device ecosystems, would the total opportunity space for independent players shrink or grow? Where are you placing your bets?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Fri, 08 Jan 2010 00:23:00 -0800 UI-driven Database Snapshot & Restore http://blog.memamsa.com/2010/01/07/ui-driven-database-snapshot-restore http://blog.memamsa.com/2010/01/07/ui-driven-database-snapshot-restore

For most people, backing application databases is usually (touch wood) a one-way operation. You take your precautionary measures, employ some kind of hosted or scripted backup solution, and hope that you only infrequently, if ever, have to restore from an old database.

But, what if you want to take a database snapshot at any time, keep a list of such snapshots and restore at will from any of them at any time? And you want to do it from the UI? Sounds far-fetched?

Here is one scenario.

  1. Your sales guy has lined up multiple demos for your app and he wants to tailor the data and demo aspects for each client.
  2. Your dev team is too busy to spend time crafting a whole new admin console just to make a whiz-bang demo.
  3. ssh? mysqldump? redirect output? >, < #@*?

With Rails and Rake, here is how you can make your sales guy happy and get him to buy you some Mai Tais.

Introduce two new rake tasks, db:snapshot and db:restore which take DIR and NAME from the environment (as well as the Rails environment).

# lib/tasks/db.rake namespace :db do   desc 'Store a snapshot of the database with the given name'   task :snapshot => :environment do     path = ENV["DIR"] || "db/snapshots"     stamp = Time.now.strftime("%Y%m%d") + Time.now.tv_sec.to_s.slice(-6..-1)     file = ENV["NAME"] || "#{stamp}_snapshot.sql"       dbconf = ActiveRecord::Base.configurations[RAILS_ENV]     dbcmd = "mysqldump -u #{dbconf['username']} -p#{dbconf['password']} "     dbcmd += "#{dbconf['database']} > #{path}/#{file}"     sh dbcmd   end     desc 'Load database from a previously stored snapshot'   task :restore => :environment do     path = ENV["DIR"] || "db/snapshots"     if ENV["NAME"]       filename = "#{path}/#{ENV["NAME"]}"       dbconf = ActiveRecord::Base.configurations[RAILS_ENV]       dbcmd = "mysql -u #{dbconf['username']} -p#{dbconf['password']} "       dbcmd += "#{dbconf['database']} < #{filename}"       sh dbcmd     else       $stderr.puts "No snapshot name provided. Nothing to do."     end   end end  

Enable controllers to invoke these rake tasks in the background.

# application_controller.rb protected def invoke_rake(task, options = {})   options[:rails_env] ||= Rails.env   args = options.map { |k, v| "#{k.to_s.upcase}='#{v}'" }   rake = "rake #{task} #{args.join(' ')} --trace 2>&1 >> #{Rails.root}/log/rake.log &"   system rake end

Wrap the snapshot storage and lookup in a pseudo-model.

# app/models/snapshot.rb class Snapshot < ActiveRecord::Base   DIR = Demo.getval('snapshots_dir') || APP_CONFIG[:snapshots_dir]   SUFFIX = APP_CONFIG[:snapshot_suffix] || '.snap.sql'     def self.all     list = []     files = Dir.glob("#{DIR}/*#{SUFFIX}")     files.each do |snap|       list << [         snap.split('/').last.split(/#{SUFFIX}/).first,         File.stat(snap).ctime       ]    end    list   end     def self.for(name)     name.gsub!(/[\s\&\@\!\#\$\%\^\*\(\)\+]/, '-')     {:dir => DIR, :name => name + SUFFIX}   end end

And put the pieces together as you want through appropriate views and controllers. (Thanks,Railscasts and Craig Ambrose)

Happy New Year!

But, wait, you want some previous year back? Sorry, we can't do that yet.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Sun, 22 Nov 2009 21:08:00 -0800 Rails-style jQuery UI Menu http://blog.memamsa.com/2009/11/22/rails-style-jquery-ui-menu http://blog.memamsa.com/2009/11/22/rails-style-jquery-ui-menu

Some people love the drop-down, drill-down fly-out menu, which is now working its way into the official jQuery UI code-base.

The menu looks great, but is a bit tedious to construct. In fact, its downright onerous for the railszers used as we are to select_tag and options_for_select.

Ruby to the rescue!

The rails-jquery-dropdown helper generates the drop-down HTML markup, places menu items and values and optionally sub-menus using a passed-in Array, and wires up the Javascript behavior using jQuery.

Get it from GitHub: http://github.com/dkeskar/rails-jquery-dropdown

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Sat, 14 Nov 2009 07:39:06 -0800 On News http://blog.memamsa.com/2009/11/14/on-news http://blog.memamsa.com/2009/11/14/on-news The TiE Oregon event on Unfolding News was a frank and insightful discussion anchored by newspaper veteran Peter Bhatia and news entrepreneur Steve Woodward. News about newspapers is either increasingly dire, or dramatic. The list of defunct newspaper continues to grow. Online, a news mogul mulls withdrawing news content from the Google index. Sitting face-to-face and talking with thoughtful people with real stories from the trenches quickly brings into focus the salient issues. Here are some of the key points from the discussion.
  1. Newspapers have historically been highly lucrative for their owners, providing greater than 25% margins. This is a for-profit business which is protected by constitutional amendments, and has enjoyed special dispensation such as preferred postal carrier rates and legal protections.
  2. Printing presses have modernized, computerized and become efficient, yet they are costly to operate. Home delivery of printed news (in its American form) involves a large distribution organization.
  3. Yet, print ads are highly lucrative. A full page spread in a metro newspapers such as The Oregonian may cost upwards of $12,000. Assuming a daily circulation of 300,000, that's the equivalent of $40 CPM. For comparison, online ad payouts are generally a small fraction even at $5, and typically just fractions of a dollar.
  4. Newspapers are thus faced with the Innovators' Dilemma. Their product offering with current technology is highly lucrative, enjoys wide margins, and faces certain decline. Yet, their organizational structure and DNA cannot embrace the cheapness of blogs and technology mediated aggregators.
  5. Newspapers are vested in their identity around investigative journalism, political coverage and social issues. Sadly, unlike financial and business news (Reuters, WSJ) or trade news, a paying market for such news content is non-existent.
  6. Newspapers and news staff are proud of their objectivity. Perversely, the audience for and profits in non-objective formats for political coverage (Rush, Lars, Glenn et al) are much higher.
With challenges like these, it was refreshing to see Peter's upbeat outlook about the future. Combining technology with editorial expertise, pioneering new content domains such as hyper-local coverage and securing a funding model for investigative journalism, Peter is confident that newspapers will thrive in the emerging Internet and device-centric world. Steve provided great insights about the art and craft of news reporting as well as some of the radical innovation underway. Steve is of course acting on the future, with Nozzl Media close to releasing a real-time mobile distribution and monetization engine for publishers. Thanks and all the best to Peter and Steve.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Fri, 13 Nov 2009 23:43:52 -0800 AirDB Join Table Attributes http://blog.memamsa.com/2009/11/13/airdb-join-table-attributes http://blog.memamsa.com/2009/11/13/airdb-join-table-attributes In some cases, it becomes necessary to have additional attributes associated with a many-many relationship. This is typically true of "has_and_belongs_to_many" associations which end up mirroring some kind of "membership" between the joined models. For example, a library system might track borrowing of books by patrons, with extra attributes for return dates and accrued fines. The Django guys have a handy example about musicians and bands with extra attributes such as the membership role and date of joining. In my case, I needed to track sharing status of Photos across Photosets. AirDB now has support for such join table attributes. Its a bit of a hack, in the interests of time, code size and abstraction concessions. The new things, which make it all possible include:
  1. An optional argument to Migrator.joinTable()
  2. DB.execute(sql) to allow tweaking an existing join table.
  3. Associator methods: setAttrfindAllByAttr, countByAttr, getAttrVal.
Here are some actual code excerpts (in the Photoset model)
// The new migration directive
   function(my:Migrator):void {
      var statusCol:Array = ['status', DB.Field.VarChar, {
         limit: 4, 'default': Photo.ShareStatus.None}
      ];
      DB.execute(
         "ALTER TABLE photos_photosets ADD COLUMN " +
         DB.fieldMap(statusCol)
      )
   }
Setting the sharing status for a particular photo in this photoset
public function photoSent(photo:Photo):void {
      this.photos.setAttr({status: Photo.ShareStatus.Sent}, photo);
   }
If no target is specified, the specified attributes are set for all associated photos in this photoset.
this.photos.setAttr({status: Photo.ShareStatus.Sent});
Count the number of photos based on some attribute.
var xfrCond:String = "status = '" + Photo.ShareStatus.Sent;
   this.photos.countByAttr(xfrCond);
Ideally, and with some coding leisure, this would be best done as a new has_many_through association. If you know of ActionScript language mechanisms to ease the implementation, I would be interested in hearing about them. Meanwhile, we have functional join tables attributes.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Fri, 11 Sep 2009 23:08:23 -0700 jQuery('.contributors').thanks(); http://blog.memamsa.com/jquerycontributorsthanks http://blog.memamsa.com/jquerycontributorsthanks I stumbled upon jQuery when it was still in its early stages when all it did was offer powerful CSS and regexp style selectors. It immediately made DOM manipulation from within JavaScript easy, simple and reliable.
Media_httpstaticjquer_berod
Within a few months of my discovery, jQuery had fixed cross-browser issues, and actually made it the choice for ensuring cross-browser support. Here are some of the things that led me to consistently choose jQuery over Prototype, even if it meant eschewing the Rails/Prototype coupling and doing things the hard way.
  • CSS-style and RegExp selectors.
  • Light-weight - smaller file size, faster download, quicker load.
  • Plays nice with others - jQuery.noConflict();
  • Many powerful mechanisms for traversing and manipulating the DOM.
  • Queue up onload logic from multiple places with jQuery(document).ready()
  • Convenient call chaining  - jQuery('#thing').doThis().that().more();
  • Extensibility and lots of plugins.
  • Excellent, fine-grained AJAX support.
With such features, it is no surprise that the jQuery has evolved into a thriving, distributed ecosystem providing innumerable plugins and UI and effects frameworks on top such as jqueryUI. Thanks to all the contributors who make it happen. jQuery("#resig,plugin.writers,.contributors").thanks();

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Tue, 11 Aug 2009 05:41:40 -0700 Labels for Software Practitioners http://blog.memamsa.com/2009/08/10/labels-for-software-practitioners http://blog.memamsa.com/2009/08/10/labels-for-software-practitioners People who earn a living writing software tend to describe themselves (and be described) in myriad different ways. Whether in blog posts, job boards, business plans and discussion forums, a few distinct terms and usage patterns emerge. All too often, names and labels end up defining, more than just denoting something. Perhaps Shakespeare was being ironic when he gave the quote about roses for Juliet to say, who then suffers so famously. Most programmers would agree that it is better to have meaningful variable names. Why then, should we not give careful considerations to how we describe ourselves? Without further ado, here are some of the terms, and their general connotations.
  1. Programmer. Quaint, archaic but retro-chic. Persists in usage despite mechanistic connotations, commonly  with linguistic prefix and sometimes with desirable attributes (e.g. pragmatic).
  2. Coder. Probable insult. Most likely used sarcastically and/or for self-denigration. Bonus points for poetic amalgamations with the rodent or primate family.
  3. Engineer. Putting code blocks together to meet specified tolerances and performance criteria. An Organization Man, probably, who develops mission-critical platforms.
  4. Developer. Bland, but with a hint of creation and coordination. Probably a more evolved specimen than a mere Programmer and more ambitious than an Engineer?
  5. Computer Scientist. A theoretical bent of mind, and mastery of algorithms. True sighting in the field are rare, but rumored to create whole new paradigms and fields of work for others to toil in.
  6. Hacker. Notions of brilliance and mental ability coupled with enthusiasm for software and systems, mostly in pulling off the unachievable. An insider's badge, since the mainstream media persists in conflating hackers and criminals.
Less common, but more fanciful are the Software Artists, Masters, Wizards and Programmer-At-Arms. So, how do you describe yourselves? PHP Programmer, Code Monkey, Application Developer, Senior Software Engineer or Kernel Hacker? Or perhaps you prefer being a Rockstar Programmer, Ninja Developer or Software Samurai?

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Tue, 04 Aug 2009 05:32:00 -0700 A Stark Example of Product Evolution http://blog.memamsa.com/2009/08/03/a-stark-example-of-product-evolution http://blog.memamsa.com/2009/08/03/a-stark-example-of-product-evolution

Today I got a really cool poster for the upcoming Iron Man sequel, which shows the Iron Man Mark 1, 2 and 3 models.  

Media_httpblogmemamsa_kdebl

As a kid, I was not a big Iron Man fan. I did like the movie, and I had always liked the way they picked that old song for the movie theme. (What's your FlixIQ on that?) But to me, the poster clearly showed product evolution in action. You only have so much time, limited resources, and few friends. You build what you can build to break out. As long as you survive, you can make improvements. But you have to keep testing and making refinements, before you get that super-cool and powerful product. It worked for Tony Stark, and it is a good visual for product evolution.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Sun, 02 Aug 2009 17:32:46 -0700 Cuing FlixIQ http://blog.memamsa.com/2009/08/02/cuing-flixiq http://blog.memamsa.com/2009/08/02/cuing-flixiq Give the Clue, Flix I Cue. That's FlixIQ. And it is now live at http://flixiq.com If you have not yet clicked to see for yourselves, here is some wordiness.

Media_httpflixiqcomim_aeafz

FlixIQ lets you cue a video clue to create and share quizzes. We are talking video clues here, which means movies, music, sports, or anything where images flickering 24 times a second (a.k.a flix) trigger some memory or mental connection. So, show off your total recall by answering those questions. If that's too easy for you, stump others by finding a telling scene, and create tough challenges for others. Verdomme, dat is kicken.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar
Thu, 30 Jul 2009 23:49:52 -0700 git init community http://blog.memamsa.com/2009/07/30/git-init-community http://blog.memamsa.com/2009/07/30/git-init-community Late in February, at the Recent Changes Camp, I noticed some familiar faces and so walked into the Calagator Hacking session, hoping to spend a few hours learning and contributing to the code. Alas, I was ill-equipped, lacking git. I had heard several people evangelize git, hold training sessions and in general rhapsodize about it. All the cool kids were using it. For several time and efficiency reasons, I had put off switching to git. Meanwhile, I was dealing with the practical annoyances, since many of my svn:externals were deserting to git repositories, forcing me to download tarballs.
Media_https3amazonaws_dkiqh
So that day, with some help from some of the friendly Calagator folks, I got myself git. From there it was a short step to using github, and short time before I switched multiple client and project repositories to git. As a result, my coding workflow has improved tremendously. Sometimes, we need a nudge to stop putting things off and start doing something that improves our lives. And community meet-ups such as RCC, BarCamp, and OSBridge, are great at connecting and catalyzing people to do just that. Thanks to all the great folks who infuse Portland with this community spirit.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/407886/headshot-120.png http://posterous.com/users/37lsKjlA5jUd Dhananjay Keskar dkeskar Dhananjay Keskar