Notes from RailsConf - Starting Up Fast: Lessons from the Rails Rumble...
Hosted by Nick Plante (Nth Interactive)
Would’ve liked to give attributions for these quotes, but it wasn’t practical. Sorry!
Rails Rumble: 48 hours to design, develop, and deploy a micro-app. Public voting. Panel: Joe Fiorini Grand prize winner, 2008 meetbetween.us Team of 4 Ben Scofield Solo Division, 2007, 2008 Forever Home (down) Chris Saylor Grand prize winner, 2007 tastyplanner.com Team of 4 James Golick Most Useful, 2008 "What Does This Error Mean?" site "How is the Rumble like working on a normal Web project? How does it differ?" Time constraint means you won't be building a social network, etc. What can you cut out? Do you need a login system, for example? People likely to visit site, make snap judgement on first page, and leave again. "Is it possible to build a real product this way? Have you continued to develop your entry apps?" Real Simple Magazine did a couple hacknights later. Someone contacted them to acquire it later. Joe got approached by yellowpages.com, though nothing has materialized yet. No matter how great your initial idea is, you don't REALLY know what you want to build until you start. Getting app active and getting feedback is great. "What sort of up-front planning and design work did you do?" Complete wireframe on pen and paper (digital wireframes not allowed), assignment of tasks to developers. "None." 5 or 10 stories in Pivotal, not much. Color selection, finding stock photos. "How much time did you spend in prep, and does that affect the spirit of the Rumble?" You can plan as much as you want if you're not creating digital assets. Much of this is on the honor system. "We didn't want to spend 48 hours thinking, [so we planned up front]." Moderator: We want to encourage use of the sea of third-party plugins that are out there. "We got shit marks for design, probably because we didn't do any." "How did you plan for the 80/20 rule? (20% of small tasks take 80% of the time.)" We ensured that even if there were small tasks we hadn't completed, we could still deploy. Ben Scofield expounds: Version he was working on at deadline had a bug, but version control let him back out to a stable version. We talked about features we wanted up front. Got a backlog going. Our mantra: "Think of Google". Try to have nothing but a search box and a couple buttons. A 48-hour competition is a terrible place to mentor someone. Make sure you know all the "Did you use automated testing when you built your application?" No. TDD can make you faster for big apps, but it slows you down on small ones. Yes, some. Yes. Automated tests are great for catching regression. It's just a good development practice. Testing is a method of design. If I need to get something done quickly and can't test, I do 'design by wishful thinking'. Write the code the way you want to see it, then go implement it. [Sounds like comment-driven development to me.] Don't let them fool you. You can still win if you don't do testing. "What plugins/gems/tools did you find most helpful?" Plugin by James Golick helped build RESTful contollers without need to code. Starter apps - Bort, Blank. Moderator: Rails 2.3 Templates offer starter-app-like functionality. Factory Girl, Shoulda, Mocha. Make Resourceful. New Relic RPM - it helped us at one point when LifeHacker post generated 2000 hits during voting period. MySQL fried, not Rails, and RPM helped spot that. Almost everyone used Campfire. Inline paste, inline images, chat history are nice. Basecamp. Pivotal Tracker. Super-lightweight tool to keep organized without eating our time. "How did you find other people to work with and decide that you could work with them? Is it anything like finding co-founders for a startup?" Talked to good friends first. At last minute, had to call every local Rails developer we knew to replace a dropout. Worked out well. Find a well-rounded team. Sysadmin, DB design, graphic design, developer. Good friends from local developer community. Wound up hiring two of them. Local user groups. Refresh to find designers. Ruby User Groups for developers. "What was the most rewarding part?" Getting to work with awesome people. Did screencast too. It was a lot of fun. Getting to know people better. Getting to release a completed app- so often, real life interferes with completing a project; not here. You get so bogged down working on large apps for an employer. This reminds you what's great about coding. Moderator: "Launching shit is awesome." "How much sleep did you get?" 4 each. 6 each. 4-6 each. One member went to concert, but coded in car on way there and way back. 6 hours per night. You don't have to work 44 of the 48 hours, just set realistic expectations.Read more...
Notes from RailsConf - Rails 3: Step Off the Golden Path...
Hosted by Matt Aimonetti.
Rails philosophy: Convention over configuration Merb philosophy: Performance Framework agnosticism Rails 3 philosophy is also a merger: Performance Modularity Framework agnosticism What you get: Public API (It was closed for Rails 2) Mountable apps (mount your blog app in your CMS app) Default stack: ActiveRecord Test::Unit Prototype ERB But, it's less opinionated: Other Javascript frameworks: jQuery MooTools ExtJS Yahoo! Other templating engines: Haml Other ORMs (turn DB records into objects): DataMapper Sequel CouchRest Other test frameworks: Cucumber RSpec When to step off the golden path: If your templating, JS, ORM, or performance requirements differ. Otherwise, use the default stack- it's real-world tested. Datamapper: Procrastination as a virtue: Lazy Loading - Don't pull fields until they're asked for specifically. Strategic Eager Loader ActiveRecord: Student.all.each.books.map {|b| b.name} select * from "students" select * from books where student_id = "1" select * from books where student_id = "2" #etc. This is slow! DataMapper: Student.all.each.books.map {|b| b.name} select id, name from students order by id select id, name, student_id from books where (student_id in (1, 2, 3, X)) order by id --Faster Multiple "repos" (databases) Config: production: adapter: mysql database: production-app host: localhost ... repositories: nightly_backup: adapter: sqlite3 database: shared/nightly.db weekly_backup: ... Then set up a task to copy from DB to repo: Article.copy(:default, :nightly_backup, :created.gt => 1.day.ago) Legacy databases: class Page include DataMapper::Resource property :id, Serial property :name, String #Specify different fields when talking to legacy database: repository(:legacy) do property :name, String, :field => "title" end end Query::Path #Joins people with addresses, finds records where street column LIKE '%street%' Person.all("addresses.street.like" => "%street%") Many adapters: RDBMS file system IMAP YAML SalesForce REST APIs your API here - write your own. Sequel High performance Sharding Prepared statements Highly customizable SQL statements Hibernate Built in sharding ActionORM JRuby Many Java libraries for legacy databases Non-RDBMS systems AppEngine::DataStore CouchRest for CouchDB Redis, Tokyo Cabinet, etc... More customizations available: File structure (including very_flat) Custom router DSL Custom request handlers class Presentation < ActionController::Http def index self.response_body = "Hello!" end end Presentation.action(:index).call(Rack::MockRequest.env_for("/railsconf"))Read more...
Notes from RailsConf - Getting to Know Ruby 1.9...
Hosted by David A. Black
1.8.6: > Object.new.to_a [#<Object...>] > "onentwonthree".to_a ["onen", "twon",...] 1.9: > (0..10).to_a [1, 2, ...] Above 1.8 items don't have .to_a, though. After all, why *should* an object know how to wrap itself in an array? > Array(Object.new) #Array now has the responsibility. [#<Object...>] 1.9: > "abc".to_i 0 > Integer("abc") Exception 1.8: > {1, 2, 3, 4} Hash 1.9: > {1 =>2, 3 => 4} Have to use hash rockets. 1.8: > String.ancestors [Enumerable, String, Comparable, ...] > "1n2n3".each{|s| puts s} 1 2 3 > "abcndefnghi".map {|s| s.reverse } 1.9: String does not mix in Enumerable > "".each NoMethodError... > "abcndefnghi".lines.each {|l| puts l.upcase} > "abcndefnghi".each_line {|l| puts l.upcase} #Equivalent > "abcndefnghi".bytes.each {|l| puts l.upcase} > "abcndefnghi".code_points.each {|l| puts l} 1.9: > str = "Give me 100u20ac" "Give me 100<Euro symbol>" > str.bytes.to_a.size 14 > str.chars.to_a.size #Shorter than .bytes due to Unicode character. 12 1.8: > str = "This isna three-nline string" str[6] #Gives the ordinal. (Kinda hacky...) 115 > str[6, 1] "s" 1.9: > str = "Give me 100u20ac" > str[2] #Gives the character (I like this better). "v" > str[2].ord 118 > str[2, 1] "v" > str[2, 5] "ve me" 1.9: > h = {:one => 1, :two => 2} > h = {one: 1, two: 2, three: 3} #New hash separator! 1.9: > link_to "click", controller: "users" #That's a hash as the last argument, braces are optional. 1.8: > {1 => 2, 3 => 4, 5 => 6} #Non-deterministic, could give {5 => 6, 3 => 4} 1.9: > {5: 6, 1: 2}.each {|k, v| p "#{k}: #{v}"} #Order is deterministic. 5: 6 1: 2 1.9: Beware: Hash#sort still returns an Array of Arrays, not a re-ordered Hash. That may change. Hash#select still returns a Hash. 1.9: Enumerable module has new methods. > a = (1 .. 10).to_a > a.each_slice(3) {|slice| p slice} [1, 2, 3] [4, 5, 6] ... [10] 1.9: > a.each_cons(3) {|cons| p cons} #Moves result start by 1 index each time. [1, 2, 3] [2, 3, 4] [3, 4, 5] 1.9: > a.one? {|i| i == 2} false > a.all? {|i| i == 2} false > a.any? {|i| i == 2} true 1.9: > ('a'..'c').cycle(2) #<Enumerator> > ('a'..'c').cycle(2).to_a ['a', 'b', 'c', 'a', 'b', 'c'] .cycle with no args loops forever. Fun, but dangerous. 1.8: > x = 1 > [10, 20, 30].each {|x| puts x * 100} 1000 2000 3000 > x == 30 true #WTF? Why not 1? Wasn't x in the block scoped only to the block? > [10, 20, 30].each {|@var| puts @var} 10 20 30 > @var 30 1.9: > x = 1 > [10, 20, 30].each {|x| puts x * 100} 1000 2000 3000 > x 1 #There we go, it wasn't overwritten. [1, 2, 3].each {|@x|} SyntaxError: formal argument cannot be an instance variable. (That's a good thing to me.)Read more...
RailsConf notes - Kevin Barnes - In Praise of Non-Fixtured data
Fixtures bad: Get highly unmanageable, especially when someone decides to import real data (:user_275, :user_276...) Live outside test. Can't change loaded values easily. Factories good: Let you use sensible labels and tweak the created data. They reduce dependence on external data (manipulate values right in the test). FactoryGirl: http://github.com/thoughtbot/factory_girl/tree/master spec/factories/first_model.rb second_model.rb... Code: Factory.define :user {|f| f.name 'Joe'; f.zip '34279'; f.association :employer} Factory(:user).should be_valid Factory(:user, :name => nil).should_not be_valid .association calls another factory (that you define) to generate associated model object. Object Daddy: http://github.com/flogic/object_daddy/tree/master spec/exemplars/*_exemplar.rb Code: class User generator_for :name => 'Test User' generator_for :ssn, :start => '12343214' do {|prev| prev.succ} end @user = User.generate! @user.should be_valid [Barnes likes ObjectDaddy. I don't 'cause of modificat Others: machinist foundry fixjourRead more...
Notes from RailsConf - ActiveScaffold BoF session...
Thanks to Mike Gaffney and Kenney Ortmann for hosting this session, and for writing a cool framework!
Install: script/plugin install git://github.com/activescaffold/active_scaffold.git Site says to pass -r rails-2.2 option; HEAD works fine for Rails 2.3. Setting up a quick test app in Rails 2.3: Create app/views/layouts/application.html.erb: Ensure it contains a default HTML document. Ensure it has in the body. Add these lines to the HEAD tag: Create a model with a few fields and a controller. On your controller, add: active_scaffold :model_name Go view the index for the model (no need to create index.html.erb, def index, etc.): You should have full CRUD, sorting by column, etc. Customizing: ActiveScaffold.set_defaults {|config| ...} in your application controller. Model-specific settings in individual controllers. Override ActiveScaffold's default views by creating a special folder in your views directory. Additional notes: Home page doesn't get updated as often as it should, but project is being actively maintained and used, and will support Rails 3.0 shortly after its release. For many-to-many relationships, you may need to have the view reference the join model. See the mailing list.
Had this up and running in 10 minutes:
Read more...