Capistrano Deployment Recipes

Posted by Raymond Law Mon, 04 Aug 2008 21:30:00 GMT

Dealistic was first deployed to Slicehost when we were testing it on staging. However, I only got the 256 slice and low memory is a big problem for Ruby and Mongrel. We’ve moved to Amazon EC2 when we launched. It is running rock solid and we don’t run out of memory again, at least for now :P

As a result of all these, I wrote two Capistrano recipes for deployment, for both Slicehost and EC2. We also use GitHub for version control. I think these deployment recipes may be helpful to others. So here they are:

We wrote some custom Capistrano tasks to copy over configuration files, symlink plugins, start/stop BackgrounDRb, and a custom maintenance page. But these things are optional. It should be simple to add/remove things as you see fit.

Dealistic is launched

Posted by Raymond Law Tue, 29 Jul 2008 06:29:00 GMT

Andrew and I have been working on a new site Dealistic after our work at OnMyList.

We’ve also put up a screencast to show off our features (HUGE thanks to Sherry)

It lets you find deals by specifying a list of tags and it can notify you by email, RSS feed, and/or SMS when new deals appear that match your tags.

We made the site because we often need to find deals on things we want to buy but we spend way too much time looking for irrelevant deals on a lot of different sites. With Dealistic, what you get is what you want.

Never miss a deal because you don’t have time to find it! Just add a tag at Dealistic and we will let you know when a deal that you are looking for appears.

We also have a feedback tool that we hope you can give us suggestions to do better.

Deploying your Rails applications with Phusion Passenger

Posted by Raymond Law Tue, 24 Jun 2008 14:00:00 GMT

There have been several methods to deploy an Ruby on Rails application. Until recently, the most popular is to run Apache and proxy balance to multiple Mongrel instances that are running simultaneously.

Passenger, developed by Phusion, is the new kid entering the Rails deployment market. We have been using the Apache PHP module for years and deploying a PHP applications is a snap. This has not been possible with Rails until Passenger. It is so easy too! You can still use Capistrano to automate deployment. I will show you how I get it to work on Ubuntu.

sudo gem install passenger
passenger-install-apache2-module

Update: Phusion just released Passenger 2.0 RC 1. You can download this version and do gem install passenger-1.9.0.gem instead. But I had an error compiling it on Mac OS X Leopard. hongli pointed me to use the version from GitHub that has the fix and it works like a charm. Thanks Phusion guys.

To get it from GitHub:

git clone git://github.com/FooBarWidget/passenger.git

I create a separate /etc/apache2/mods-available/passenger.load and it contains the following:

For 1.0.5:

LoadModule passenger_module /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/ext/apache2/mod_passenger.so
RailsSpawnServer /usr/local/lib/ruby/gems/1.8/gems/passenger-1.0.5/bin/passenger-spawn-server
RailsRuby /usr/local/bin/ruby

For the GitHub version (Of course the path will look different depending on where your git clone is):

LoadModule passenger_module /home/rlaw/downloads/passenger/ext/apache2/mod_passenger.so
PassengerRoot /home/rlaw/downloads/passenger
PassengerRuby /usr/local/bin/ruby

I then tell Apache to load the Passenger module:

a2enmod passenger

Now, I create a virtual host configuration for one of my Rails app in /etc/apache2/sites-available/dealistic:

<VirtualHost *:80>
  ServerAdmin webmaster@dealistic.com
  ServerName dealistic.com

  DocumentRoot /home/deploy/apps/dealistic/current/public

  <Directory /home/deploy/apps/dealistic/current/public>
    Options FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
  </Directory>

  LogLevel warn
  ErrorLog /var/log/apache2/dealistic/error.log
  CustomLog /var/log/apache2/dealistic/access.log combined
</VirtualHost>

I then restart Apache:

sudo /etc/init.d/apache2 reload

When you need to restart your application because you have changed some code that Rails does not reload in production, just do:

touch /home/deploy/apps/dealistic/current/tmp/restart.txt

I have not tried their Ruby Enterprise Edition yet. They claim substantial memory and speed improvement at RailsConf 2008, so it will be interesting to see.

Badger Rails Plugin

Posted by Raymond Law Mon, 23 Jun 2008 14:00:00 GMT

(I also posted about this plugin in the Intridea blog )

Badger (hosted at GitHub) is a simple Rails plugin that creates badges. A site often allows its users to upload a profile image. A profile image is just that, an image resized to fit in a predefined space to show up in the user’s profile.

With Badger, you can have something prettier – a badge that shows the user-uploaded image on top of another image that identifies the user as a part of the community. We have company badges, security badges, so why not web badges to have your users show off his/her affection for your site?

Badger works by accepting cropping parameters of the overlay image in a hash (x1, y1, width, height), which is used to crop the overlay image. It then resizes the cropped image to the size specified by composite_width and composite_height in badger.yml. Finally, it places the resized image on top of the background image at location specified by composite_x and composite_y in badger.yml. The resulting image is saved back to either the filesystem or Amazon S3, using attachment_fu.

Badger requires the attachment_fu plugin, ImageMagick, and MiniMagick. Also, the JavaScript Image Cropper UI can be used to obtain the cropping parameters from the users.

For example:

+ =

Here I overlay RUBY on top of JAVA to produce I LOVE RUBY.

Back from RailsConf 2008

Posted by Raymond Law Wed, 04 Jun 2008 15:31:00 GMT

Photos posted to my flickr.

Attending RailsConf 2008

Posted by Raymond Law Fri, 23 May 2008 20:29:00 GMT

I will be attending the RailsConf from 5/29 to 6/1 in Portland with my colleagues from Intridea. It is going to be great to see the whole team there, and attend the different sessions. I am really excited to meet other Rails enthusiasts and talk about projects we are working on.

We will be helping with the Community Project Code-Drive on 5/29 from 10am to 5pm. Come check us out.

Josh Owens and Chris Selmer will also be presenting Building an app in 48 hours – A Rails Rumble Case Study to talk about their fast developments in their participation of the Rails Rumble event. Josh won first place with Tasty Planner in the event! Chris participated as a solo team on Your Pet Records. Come attend their session to see how they developed an app in just 48 short hours!

Tricky Git Submodule 1

Posted by Raymond Law Tue, 29 Apr 2008 05:03:00 GMT

I recently spent a good amount of time figuring out why the acts_as_taggable_on plugin did not work for me. I used Git’s submodule to grab the code fom GitHub.

> git submodule add git://github.com/mbleigh/acts-as-taggable-on.git vendor/plugin/acts-as-taggable-on

It seems logical to name my plugin directory with dashes since that’s what the path suggests, right? Wrong! If you do that, it does not work because the plugin expects underscores. This is probably due to the way Rails finds and loads the plugins, I guess. Haven’t had time to really dig deep into that…

Use this instead:

> git submodule add git://github.com/mbleigh/acts-as-taggable-on.git vendor/plugin/acts_as_taggable_on

I initially didn’t pay attention to this because before Git, I just used:

> script/plugin install http://svn.intridea.com/svn/public/acts_as_taggable_on/

I did not have to explicitly tell where to put the plugin. script/plugin is a Rails thing while Git is not.

Hopefully anyone who gets tripped up by this in the future will find out this post.

Using Git Branches and Stash

Posted by Raymond Law Sun, 27 Apr 2008 14:50:00 GMT

I recently started to learn and use Git for one of my projects. Git encourages easy and cheap branching, here’s what I do with Git branches and stash to switch between branches while working on different things.

Assume we want to develop yet another blog engine with Rails:

Create the application. No surprise here!

> rails -d mysql blog
> cd blog

Initialize the Git repository. This will create a .git/ directory in your project.

> git init
Initialized empty Git repository in .git/

Add everything in your project directory for the next commit to Git.

> git add .

Lets see what will be commited.

> git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#    new file: README
#    new file: Rakefile
#    new file: app/controllers/application.rb
#    new file: app/helpers/application_helper.rb
#    new file: config/boot.rb
#    new file: config/database.yml
#    new file: config/environment.rb
#    new file: config/environments/development.rb
#    new file: config/environments/production.rb
#    new file: config/environments/test.rb
#    new file: config/initializers/inflections.rb
#    new file: config/initializers/mime_types.rb
#    new file: config/routes.rb
#    new file: doc/README_FOR_APP
#    new file: log/development.log
#    new file: log/production.log
#    new file: log/server.log
#    new file: log/test.log
#    new file: public/.htaccess
#    new file: public/404.html
#    new file: public/422.html
#    new file: public/500.html
#    new file: public/dispatch.cgi
#    new file: public/dispatch.fcgi
#    new file: public/dispatch.rb
#    new file: public/favicon.ico
#    new file: public/images/rails.png
#    new file: public/index.html
#    new file: public/javascripts/application.js
#    new file: public/javascripts/controls.js
#    new file: public/javascripts/dragdrop.js
#    new file: public/javascripts/effects.js
#    new file: public/javascripts/prototype.js
#    new file: public/robots.txt
#    new file: script/about
#    new file: script/console
#    new file: script/destroy
#    new file: script/generate
#    new file: script/performance/benchmarker
#    new file: script/performance/profiler
#    new file: script/performance/request
#    new file: script/plugin
#    new file: script/process/inspector
#    new file: script/process/reaper
#    new file: script/process/spawner
#    new file: script/runner
#    new file: script/server
#    new file: test/test_helper.rb
#

Lets do our first commit.

> git commit -m 'Initial commit'
Created initial commit aa5e7a0: Initial commit
 43 files changed, 8362 insertions(+), 0 deletions(-)
 create mode 100644 README
 create mode 100644 Rakefile
 create mode 100644 app/controllers/application.rb
 create mode 100644 app/helpers/application_helper.rb
 create mode 100644 config/boot.rb
 create mode 100644 config/database.yml
 create mode 100644 config/environment.rb
 create mode 100644 config/environments/development.rb
 create mode 100644 config/environments/production.rb
 create mode 100644 config/environments/test.rb
 create mode 100644 config/initializers/inflections.rb
 create mode 100644 config/initializers/mime_types.rb
 create mode 100644 config/routes.rb
 create mode 100644 doc/README_FOR_APP
 create mode 100644 log/development.log
 create mode 100644 log/production.log
 create mode 100644 log/server.log
 create mode 100644 log/test.log
 create mode 100644 public/.htaccess
 create mode 100644 public/404.html
 create mode 100644 public/422.html
 create mode 100644 public/500.html
 create mode 100755 public/dispatch.cgi
 create mode 100755 public/dispatch.fcgi
 create mode 100755 public/dispatch.rb
 create mode 100644 public/favicon.ico
 create mode 100644 public/images/rails.png
 create mode 100644 public/index.html
 create mode 100644 public/javascripts/application.js
 create mode 100644 public/javascripts/controls.js
 create mode 100644 public/javascripts/dragdrop.js
 create mode 100644 public/javascripts/effects.js
 create mode 100644 public/javascripts/prototype.js
 create mode 100644 public/robots.txt
 create mode 100755 script/about
 create mode 100755 script/console
 create mode 100755 script/destroy
 create mode 100755 script/generate
 create mode 100755 script/performance/benchmarker
 create mode 100755 script/performance/profiler
 create mode 100755 script/performance/request
 create mode 100755 script/plugin
 create mode 100755 script/process/inspector
 create mode 100755 script/process/reaper
 create mode 100755 script/process/spawner
 create mode 100755 script/runner
 create mode 100755 script/server
 create mode 100644 test/test_helper.rb

Our project is in the Git repository now. Lets see what branches it currently has.

> git branch
* master

It only has one branch called master, which is the default branch created by Gik, a.k.a. Subversion’s trunk.

Our blog is going to have posts and comments. So we probably should create the Post and Comment resources. Before we do that, lets do some forward thinking. While working on the blog, we likely will be working with posts and comments at the same time. It will be confusing and unnessarily consume our brain cells if we were to remember which files and changes are for fixing a bug in posts or comments. It may be a good idea to create separate branches for working on posts and comments. So lets do that first.

> git branch posts
> git branch comments

Use gitk to show a visual picture of where we are.

> git branch
  comments
* master
  posts

So we have three branches: master, posts, and comments. We are currently working in the master branch. Great!

Lets switch to the posts branch.

> git checkout posts
Switched to branch "posts"
> git branch
  comments
  master
* posts

We are now ready to generate our resources

> script/generate resource post title:string body:text published:boolean

And add and commit these new files to our Git repository.

> git add .
> git commit -m 'Created Post resource'
Created commit 1ec37dc: Created Post resource
 8 files changed, 50 insertions(+), 0 deletions(-)
 create mode 100644 app/controllers/posts_controller.rb
 create mode 100644 app/helpers/posts_helper.rb
 create mode 100644 app/models/post.rb
 create mode 100644 db/migrate/001_create_posts.rb
 create mode 100644 test/fixtures/posts.yml
 create mode 100644 test/functional/posts_controller_test.rb
 create mode 100644 test/unit/post_test.rb

If we switch back to our master branch, we find that the Post resource we just created is gone! Don’t worry. They are in the posts branch but not in the master branch. Gitk shows this.

Lets switch to the comments branch and create the Comment resource.

> git checkout comments
Switched to branch "comments"
> script/generate resource comment name:string blog:string body:text
> git add .
> git commit -m 'Created Comment resource'
Created commit 7f110d3: Created Comment resource
 8 files changed, 50 insertions(+), 0 deletions(-)
 create mode 100644 app/controllers/comments_controller.rb
 create mode 100644 app/helpers/comments_helper.rb
 create mode 100644 app/models/comment.rb
 create mode 100644 db/migrate/001_create_comments.rb
 create mode 100644 test/fixtures/comments.yml
 create mode 100644 test/functional/comments_controller_test.rb
 create mode 100644 test/unit/comment_test.rb

Now we created a Post resource in the posts branch and a Comment resource in the comments branch. We want to merge them back together to the master branch.

> git checkout master
Switched to branch "master"
> git merge posts
Updating c680d0c..1ec37dc
Fast forward
 app/controllers/posts_controller.rb      |    2 ++
 app/helpers/posts_helper.rb              |    2 ++
 app/models/post.rb                       |    2 ++
 config/routes.rb                         |    2 ++
 db/migrate/001_create_posts.rb           |   15 +++++++++++++++
 test/fixtures/posts.yml                  |   11 +++++++++++
 test/functional/posts_controller_test.rb |    8 ++++++++
 test/unit/post_test.rb                   |    8 ++++++++
 8 files changed, 50 insertions(+), 0 deletions(-)
 create mode 100644 app/controllers/posts_controller.rb
 create mode 100644 app/helpers/posts_helper.rb
 create mode 100644 app/models/post.rb
 create mode 100644 db/migrate/001_create_posts.rb
 create mode 100644 test/fixtures/posts.yml
 create mode 100644 test/functional/posts_controller_test.rb
 create mode 100644 test/unit/post_test.rb
> git merge comments
Auto-merged config/routes.rb
CONFLICT (content): Merge conflict in config/routes.rb
Automatic merge failed; fix conflicts and then commit the result.

Oops! There seems to be a config in config/routes.rb. Lets see what is in that file.

ActionController::Routing::Routes.draw do |map|
<<<<<<< HEAD:config/routes.rb
  map.resources :posts
=======
  map.resources :comments
>>>>>>> comments:config/routes.rb

  # The priority is based upon order of creation: first created -> highest priority.

  # Sample of regular route:
  #   map.connect 'products/:id', :controller => 'catalog', :action => 'view'
  # Keep in mind you can assign values other than :controller and :action

  # Sample of named route:
  #   map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
  # This route can be invoked with purchase_url(:id => product.id)

  # Sample resource route (maps HTTP verbs to controller actions automatically):
  #   map.resources :products

  # Sample resource route with options:
  #   map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get }

  # Sample resource route with sub-resources:
  #   map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller

  # Sample resource route within a namespace:
  #   map.namespace :admin do |admin|
  #     # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb)
  #     admin.resources :products
  #   end

  # You can have the root of your site routed with map.root -- just remember to delete public/index.html.
  # map.root :controller => "welcome"

  # See how all your routes lay out with "rake routes"

  # Install the default routes as the lowest priority.
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
end

Ah, when we generated the resources, they edited the same line on the file. That’s an easy fix. Just get rid of the conflict markers. Merge again.

> git add .
> git commit -m 'Merged from comment branch.  Resolved config/routes.rb'
Created commit cfb3b0e: Merged from comment branch.  Resolved config/routes.rb
 8 files changed, 49 insertions(+), 0 deletions(-)
 create mode 100644 app/controllers/comments_controller.rb
 create mode 100644 app/helpers/comments_helper.rb
 create mode 100644 app/models/comment.rb
 create mode 100644 db/migrate/001_create_comments.rb
 create mode 100644 test/fixtures/comments.yml
 create mode 100644 test/functional/comments_controller_test.rb
 create mode 100644 test/unit/comment_test.rb

Now we have both Post and Comment resources in our master branch. At this point, we can delete the posts and comments branches.

> git branch -d posts
Deleted branch posts.
> git branch -d comments
error: The branch 'comments' is not an ancestor of your current HEAD.
If you are sure you want to delete it, run 'git branch -D comments'.

Since we manually merge and fix the conflict, Git is complaining that it is unsafe to delete the comments branch since we could lose some unmerged changes. But we know we already have them in the master branch.

> git branch -D comments
Deleted branch comments.

Lets establish some ActiveRecord relationships. Before we do that, lets create another branch called relationships.

> git branch relationships
> git checkout relationships
Switched to branch "relationships"

Add the one-to-many relationship to post.rb.

class Post < ActiveRecord::Base
  has_many :comments
end

At this point, lets assume our customer notifies us there is an urgent bug in the master branch. We want to make them happy, so we will temporarily suspend our work in the relationships branch and fix the bug in the master branch, before we come back to finish our work in the relationships branch.

We use a stash to do that.

> git stash save
Saved working directory and index state "WIP on relationships: cfb3b0e... Merged from comment branch.  Resolved config/routes.rb"
HEAD is now at cfb3b0e... Merged from comment branch.  Resolved config/routes.rb

The git-stash man page says:

Use git-stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away and reverts the working directory to match the HEAD commit.

A few more stash commands.

> git stash list
stash@{0}: WIP on relationships: cfb3b0e... Merged from comment branch. Resolved config/routes.rb
> git stash show
 app/models/post.rb |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
> git stash show -p
diff --git a/app/models/post.rb b/app/models/post.rb
index 791dcb5..6ad2382 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -1,2 +1,3 @@
 class Post < ActiveRecord::Base
+  has_many :comments
 end

Our changes are now saved to the stash, as evidenced by running git status.

> git status
# On branch relationships
nothing to commit (working directory clean)

Lets fix the urgent bug in the master branch.

> git checkout master
Switched to branch "master"

It turns out the bug is really trivial.

> rm public/index.html
> git commit -a -m 'Fixed urgent bug'
Created commit 9a6dcf7: Fixed urgent bug
 1 files changed, 0 insertions(+), 277 deletions(-)
 delete mode 100644 public/index.html

We can resume our work in the relationships branch now. We need to retrieve the work we have done so far in the branch from the stash.

> git checkout relationships
Switched to branch "relationships"
> git stash apply
# On branch relationships
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#    modified:   app/models/post.rb
#
no changes added to commit (use "git add" and/or "git commit -a")

Lets finish our relationship modeling by modifying comment.rb

class Comment < ActiveRecord::Base
  belongs_to :post
end

We are ready to commit our changes now.

> git commit -a -m 'Added post-comment relationship'
Created commit f71752b: Added post-comment relationship
 2 files changed, 2 insertions(+), 0 deletions(-)

A quick peek at gitk.

We can merge the relationships branch to the master branch now.

> git checkout master
Switched to branch "master"
> git merge relationships
Merge made by recursive.
 app/models/comment.rb |    1 +
 app/models/post.rb    |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)
> git branch -d relationships
Deleted branch relationships.

We can now clear our stash because we already have the changes.

> git stash clear

Final picture.

Yay!

Test/Behavior-driven development

Posted by Raymond Law Wed, 26 Mar 2008 02:50:00 GMT

I have done testing using the Rails testing framework (test-driven development) and also am looking at RSpec (behavior-driven development), so I asked Chad Fowler about his view on the two approaches. He told me the inventor of behavior-driven development said to him:

“You don’t need to do behavior-driven development because you already know behavior-driven development.”

Translation: TDD and BDD are basically the same thing. If you really understand what TDD is about, you are already doing BDD, regardless which testing framework you are using.

I also asked him how long it takes to do TDD/BDD versus w/o any testing. He answer:

“Negative twenty percent.”

A lot of existing projects don’t follow TDD/BDD and it is difficult/impossible to get involved in the middle and do that because development time is expected and it is less motivating when you are the only developer who writes tests.

Therfore, one thing I am determined to do from now on is that for my next Rails personal project, before I write any code, I will write a test to fail and then write code to make it pass.

Initially, it may take more time and getting used to, but hopefully it will cut down on debugging time and redesigning later on in the development process.

I’ve heard about TDD/BDD for quite some time and have also tried for some personal projects. But I think I will really force myself to strictly follow this paradigm, so I can get a real feel of how well it works.

Entrepreneurial Psychology

Posted by Raymond Law Wed, 26 Mar 2008 02:15:00 GMT

This is a very entertaining article by Marc Andreessen about Charlie Munger’s Poor Charlie’s Almanack. The following are some of the quotes that I find particularly interesting and it resonates with me. I can go back to read this to remind myself of some of these principles instead of reading the whole long article.

One: Reward and Punishment Superresponse Tendency

This is why stock options work so well in startups – and the fewer people in a startup, the better stock options work, since when there are only a few people in a company, it’s usually crystal clear to each person how her work will impact the value of the company.

As a company grows, stock options and other forms of equity-based motivation become less and less useful as an incentive tool, since it becomes harder for many employees in a large company to see how their individual behavior would have any effect on the stock price of the overall corporation. So, more tactical incentives kick in, such as cash bonuses.

Even engineers need counter-goals: incent engineers based purely on a ship date, and you’ll get a shipping product with lots of bugs. Incent based on number of bugs fixed, and you’ll never get any new features. And so on.

Two: Liking/Loving Tendency

Second, an entrepreneur, like any manager, has to fire people who aren’t great or who aren’t right for the tasks at hand. This naturally makes people not like you, particularly the people you fire. But again, not doing this backfires: nobody great wants to be in a company populated by mediocre or ill-fitting peers.

Finally, some entrepreneurs have emotional resistance to pursuing a strategy that does not meet with immediate approval from press, analysts, and other entrepreneurs. This is worth watching carefully – if everyone agrees right up front that whatever you are doing makes total sense, it probably isn’t a new and radical enough idea to justify a new company.

Three: Disliking/Hating Tendency

So when your startup’s competitive juices get flowing – especially for the first time – and you find yourself fixated on a competitor, be sure to take a step back and say, is this really what we want to be focused on right now – is the market we’re both in really large enough to warrant this? If so, sure, go for it, guns blazing. But if not, stepping back and thinking about how to focus instead on creating a large market might be more valuable.

Four: Doubt-Avoidance Tendency

In my view, entrepreneurial judgment is the ability to tell the difference between a situation that’s not working but persistence and iteration will ultimately prove it out, versus a situation that’s not working and additional effort is a destructive waste of time and radical change is necessary.

Five: Inconsistency-Avoidance Tendency

I think this is something that every entrepreneur needs to watch very carefully. Sometimes it’s simply a matter of timing – and if people just aren’t ready for a new idea, you usually can’t make them ready, and you have to wait for them to change or for a new generation of customers to come along.

My favorite way around this problem is the one identified by Clayton Christensen in The Innovator’s Dilemma: don’t go after existing customers in a category and try to get them to buy something new; instead, go find the new customers who weren’t able to afford or adopt the incarnation of the status quo.

Six: Curiosity Tendency

The only important thing I can think to add – aside from the importance of hiring curious people – is that lack of curiosity can be a huge danger to a startup in the following way: often, your initial strategy won’t quite work, but you can learn as you go based on other things that happen in the market and eventually iterate into a strategy that does work. Obviously, insufficient curiosity can prevent you from seeing the new data and lead you to continue to pursue a losing strategy even when you wouldn’t have to.

Older posts: 1 2 3