1. Ignore database.yml and secrets.yml by adding it to .gitignore 2. gem install sunzi (Does not have to be in Gemfile) 3. cd config 4. sunzi create 5. In a temp directory : git clone git@github.com:crslade/sunzi-recipes.git sunzi-template 6. In the project directory cd config/sunzi/ cp ~/temp/sunzi-template/files/* files cp ~/temp/sunzi-template/recipes/* recipes cp ~/temp/sunzi-template/sunzi.yml . cp ~/temp/sunzi-template/install.sh . 7. sunzi.yml has password. Do not checkin into git. Same thing for deploy_key. Add sunzi.yml and deploy_key to config/sunzi/.gitignore # Ignore sensitive data sunzi.yml files/deploy_key 8. [todo/config/sunzi] cp sunzi.yml sunzi.sample.yml cp files/deploy_key files/deploy_key.sample (Deploy user can login without password) 9. cp ~/.ssh/id_rsa.pub files/deploy_key 10. define database name, password, deploy_user = deploy, app_name=todo in sunzi.yml 11. Manual Steps. Some of these can be automated. Since it is one time thing, it is ok to do it manually. Login to VPS. Create a linode instance by selecting the plan, location. Add the public ssh key of laptop so that you can login to the instance as a root user. $cat ~/.ssh/id_rsa.pub $root@192.155.81.222 #mkdir .ssh #paste id_rsa.pub content in .ssh/authorized_keys #chown -R root:root .ssh #chmod 700 .ssh #chmod 600 .ssh/authorized_keys #exit $ssh root@192.155.81.222 should not prompt for any password AUTOMATE THIS TASK LATER. 12. Copy the IP address from your Linode dashboard and ssh root@ip-address You should be able to login into the instance without providing any password. 13. sunzi compile 14. sunzi deploy ip-address This will take 10 to 15 minutes. 15. Hit the IP address on the browser. You will see the nginx static page. 16. ssh deploy@ip-address should take into the instance without requiring any password. 17. github.com/talkingquickly/capistrano-3-rails-template copy the clone url and download this project. [temp]$ git clone url cap-template 18. [todo] Gemfile # Use unicorn as the app server gem 'unicorn' # Use Capistrano for deployment group :development do gem 'capistrano-rails' gem 'capistrano-bundler' gem 'capistrano-rbenv', "~> 2.0" end Refer the : https://github.com/crslade/todo-sunzi-deploy or temp/todo-sunzi-deploy bundle install 19. bundle exec cap install Capfile : # Load DSL and Setup Up Stages require 'capistrano/setup' # Includes default deployment tasks require 'capistrano/deploy' # Includes tasks from other gems included in your Gemfile # # For documentation on these, see for example: # # https://github.com/capistrano/rvm # https://github.com/capistrano/rbenv # https://github.com/capistrano/chruby # https://github.com/capistrano/bundler # https://github.com/capistrano/rails # # require 'capistrano/rvm' require 'capistrano/rbenv' # require 'capistrano/chruby' require 'capistrano/bundler' require 'capistrano/rails/assets' require 'capistrano/rails/migrations' # Loads custom tasks from `lib/capistrano/tasks' if you have any defined. Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r } Dir.glob('lib/capistrano/**/*.rb').each { |r| import r } 20. In project root directory: cp ~/temp/cap-template/lib/capistrano/*.rb lib/capistrano cp ~/temp/cap-template/lib/capistrano/tasks/* lib/capistrano/tasks cp ~/temp/cap-template/config/deploy.rb config/deploy.rb cp ~/temp/cap-template/config/deploy/production.rb config/deploy/production.rb mkdir config/deploy/shared cp ~/temp/cap-template/config/deploy/shared/* config/deploy/shared 21. Edit deploy.rb application name repo url ruby version linked_files secrets.yml config_files secrets.yml 22. Create deploy/shared/secrets.yml.erb Copy secrets.yml into the erb file and retain only production. 23. Find out how to setup staging server. Leave staging.rb as it is for now. 24. In deploy/production.rb Specify the server_name as IP address or as domain name if DNS is already setup. The IP also goes into server line. 25. cap production deploy:setup_config 26. ssh deploy@ip-add cd apps/todo_prod/shared/config cp secrets.sample.yml to secrets.yml cp database.sample.yml database.yml THIS STEP CAN BE DONE USING SSHKIT SCRIPT OR WRAP SSHKIT TASK IN A RAKE TASK. 27. commit all changes to git and push it to bitbucket. 28. cap production deploy 29. Reload the webpage. The application should be running. 30. To troubleshoot: Unicorn log files. Output of deployment. nginx log files and app log files.
Monday, June 22, 2015
Deploy Rails 4.1 App with Sunzi and Capistrano 3 Notes from Screencast
nginx error log file location
You can find the location of the nginx error log file in your ngnix configuration file:
/etc/nginx# cat nginx.conf
user www-data;
worker_processes 4;
error_log /var/log/nginx/error.log;
In this case, the error log is in /var/log/nginx/ directory.
Rails Basics : Using Dropdowns
I have created a sample project with detailed instructions on how to create drop-downs in Rails 4.2.2 and Ruby 2.2.2 https://rubyplus.com/articles/2501
RVM PATH Problem
Warning! PATH is not properly set up, '/Users/zepho/.rvm/gems/ruby-2.1.2/bin' is not at first place,
usually this is caused by shell initialization files - check them for 'PATH=...' entries,
it might also help to re-add RVM to your dotfiles: 'rvm get stable --auto-dotfiles',
to fix temporarily in this shell session run: 'rvm use ruby-2.1.2'.
usually this is caused by shell initialization files - check them for 'PATH=...' entries,
it might also help to re-add RVM to your dotfiles: 'rvm get stable --auto-dotfiles',
to fix temporarily in this shell session run: 'rvm use ruby-2.1.2'.
Resolution: rvm get stable --auto-dotfiles
Pongal Gem Released
Pongal is a valid US state generator that can be used in Geocoding applications. Check it out: https://rubygems.org/gems/pongal
How to generate a random number in a range in Ruby 2.2.2
rand(0..4)
This will generate random numbers 0 to 4. It is inclusive of the lower and upper bound in the range.
This will generate random numbers 0 to 4. It is inclusive of the lower and upper bound in the range.
Sunday, June 21, 2015
Implicit Vs Explicit Return in Ruby
You can run the following code at RubyPlus Code Editor:
Implicit return:
def times_ten(integer)
integer * 10
end
p times_ten(1)
Explicit return:
def times_ten(integer)
return integer * 10
end
p times_ten(2)
Implicit return:
def times_ten(integer)
integer * 10
end
p times_ten(1)
Explicit return:
def times_ten(integer)
return integer * 10
end
p times_ten(2)
Saturday, June 20, 2015
dyld: Library not loaded
dyld: Library not loaded: /usr/local/lib/libruby.1.9.1.dylib
Referenced from: /usr/local/bin/ruby
Reason: image not found
Trace/BPT trap: 5
Resolution: gem install bundler
Thursday, June 18, 2015
Wednesday, June 17, 2015
Top 6 Ruby Links for June 17, 2015
1. How a Bug in My Ruby Code Cost Code School $13,000
2. Docker Basics : Running a Nginx in a Container
3. Ruby events (meetups, conferences, camps, etc.) from around the world
4. When should you use DateTime and when should you use Time?
5. Understanding the rails-jquery CSRF vulnerability (CVE-2015-1840)
6. Mutation testing for Ruby
2. Docker Basics : Running a Nginx in a Container
3. Ruby events (meetups, conferences, camps, etc.) from around the world
4. When should you use DateTime and when should you use Time?
5. Understanding the rails-jquery CSRF vulnerability (CVE-2015-1840)
6. Mutation testing for Ruby
VirtualBox 4.3 and Vagrant 1.7.2
Vagrant has detected that you have a version of VirtualBox installed
that is not supported. Please install one of the supported versions
listed below to use Vagrant:
4.0, 4.1, 4.2
Reason : VirtualBox 4.3.28 is not compatible with Vagrant 1.0.5
1. Check :
vagrant --version
Vagrant version 1.0.5
2. Delete the Vagrant folder in Applications.
3. Download the latest vagrant from : http://www.vagrantup.com/downloads
I installed vagrant 1.7.2. This is compatible with VirtualBox 4.3
that is not supported. Please install one of the supported versions
listed below to use Vagrant:
4.0, 4.1, 4.2
Reason : VirtualBox 4.3.28 is not compatible with Vagrant 1.0.5
1. Check :
vagrant --version
Vagrant version 1.0.5
2. Delete the Vagrant folder in Applications.
3. Download the latest vagrant from : http://www.vagrantup.com/downloads
I installed vagrant 1.7.2. This is compatible with VirtualBox 4.3
Monday, June 15, 2015
Sunday, June 14, 2015
Wednesday, June 10, 2015
Using Custom Fonts in Rails 4.2
There is no need to configure anything as long as you have fonts copied to app/assets/fonts directory. Make sure to use the font-url to use custom fonts. You can see this font in action at RubyPlus. My style.css.scss looks like this :
@font-face {
font-family: 'OpenSans-Bold';
src:font-url('OpenSans-Bold.ttf');
}
@font-face {
font-family: 'OpenSans-BoldItalic';
src:font-url('OpenSans-BoldItalic.ttf');
}
@font-face {
font-family: 'OpenSans-ExtraBold';
src:font-url('OpenSans-ExtraBold.ttf');
}
@font-face {
font-family: 'OpenSans-ExtraBoldItalic';
src:font-url('OpenSans-ExtraBoldItalic.ttf');
}
@font-face {
font-family: 'OpenSans-Italic';
src:font-url('OpenSans-Italic.ttf');
}
@font-face {
font-family: 'OpenSans-Light';
src:font-url('OpenSans-Light.ttf');
}
@font-face {
font-family: 'OpenSans-LightItalic';
src:font-url('OpenSans-LightItalic.ttf');
}
@font-face {
font-family: 'OpenSans-Regular';
src:font-url('OpenSans-Regular.ttf');
}
@font-face {
font-family: 'OpenSans-Semibold';
src:font-url('OpenSans-Semibold.ttf');
}
@font-face {
font-family: 'OpenSans-SemiboldItalic';
src:font-url('OpenSans-SemiboldItalic.ttf');
}
font-family: 'OpenSans-Bold';
src:font-url('OpenSans-Bold.ttf');
}
@font-face {
font-family: 'OpenSans-BoldItalic';
src:font-url('OpenSans-BoldItalic.ttf');
}
@font-face {
font-family: 'OpenSans-ExtraBold';
src:font-url('OpenSans-ExtraBold.ttf');
}
@font-face {
font-family: 'OpenSans-ExtraBoldItalic';
src:font-url('OpenSans-ExtraBoldItalic.ttf');
}
@font-face {
font-family: 'OpenSans-Italic';
src:font-url('OpenSans-Italic.ttf');
}
@font-face {
font-family: 'OpenSans-Light';
src:font-url('OpenSans-Light.ttf');
}
@font-face {
font-family: 'OpenSans-LightItalic';
src:font-url('OpenSans-LightItalic.ttf');
}
@font-face {
font-family: 'OpenSans-Regular';
src:font-url('OpenSans-Regular.ttf');
}
@font-face {
font-family: 'OpenSans-Semibold';
src:font-url('OpenSans-Semibold.ttf');
}
@font-face {
font-family: 'OpenSans-SemiboldItalic';
src:font-url('OpenSans-SemiboldItalic.ttf');
}
Top 6 Ruby Links for June 10, 2015
1. Wrapper for the confreaks API. Browse and download convention videos from the command line.
2. Object Oriented Design Basics : Open Closed Principle
3. Nothing is Something
4. Functional Programming dictionary with Ruby #1/2
5. Cells 4.0 – Goodbye Rails! Hello Ruby!
6. How to Deal With and Eliminate Flaky Tests
2. Object Oriented Design Basics : Open Closed Principle
3. Nothing is Something
4. Functional Programming dictionary with Ruby #1/2
5. Cells 4.0 – Goodbye Rails! Hello Ruby!
6. How to Deal With and Eliminate Flaky Tests
Monday, June 08, 2015
ssh-copy-id: command not found
1. If it is already installed: brew unlink ssh-copy-id
2. brew install ssh-copy-id
2. brew install ssh-copy-id
Sunday, June 07, 2015
Thursday, June 04, 2015
Top 6 Ruby Links for June 4, 2015
1. High level Rails testing using Capybara and Minitest
2. Don't use before_action to load data
3. Capturing stdout & stderr from shell commands via Ruby
4. Empty? vs blank? vs any? – why you should not use any? to test if there’s anything in the array
5. Practicing Ruby Contributors Fund
6. A week with a Rails Security Strategy: More security, new habits
2. Don't use before_action to load data
3. Capturing stdout & stderr from shell commands via Ruby
4. Empty? vs blank? vs any? – why you should not use any? to test if there’s anything in the array
5. Practicing Ruby Contributors Fund
6. A week with a Rails Security Strategy: More security, new habits
Monday, June 01, 2015
Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
In development.rb:
config.action_mailer.default_url_options = { :host => 'localhost' }
config.action_mailer.default_url_options = { :host => 'localhost' }
Thursday, May 28, 2015
Practical Object Oriented Design in Ruby Book Review
Rating : 3 out of 5 stars.
Things I liked:
1. The discussion of how messages form the basis for a good design and she classified what type of tests should be written in each case.2. How TDD does not magically create design and how to apply good design principles as you code.
3. Writing contract tests to avoid problems due to mock abuse.
4. Guidelines for public interface.
Things I did not like:
1. Lot of fluff during the discussions. It is better to move them to her blog and make the book concise.2. The cure is worse than the disease. Using template methods to avoid calling super.
3. Using toy examples in Bicyle domain is annoying.
4. She talks about coupling without covering the basics of coupling.
Content Review
Her Suggestion:Hide the variables, even from the class that defines them, by wrapping them in methods.
My Thoughts:
#1 : If the class is small and has single purpose, this is not required. You can avoid the downside of exposing data and avoid the risk of name changes.
#2 : Her example of RevealingReferences class is an example for Data Coupling. The example of isolating knowledge of the data structure is an example of Localized Change.
Understanding Dependencies
#3. Coupling to a concrete class name. Coupling to a message name. Knowing the parameters and it's order is an example of Parameter Coupling.
#4. She probably forgot to mention in the section on Writing Loosely Coupled Code, 'If a class has too many arguments then it is likely that it violates Single Purpose Principle.
#5. Minimizing context is about providing a service.
#6. The diagram 4.7 is about raising the level of abstraction. There can be many ways to prepare for a trip. This flexibility allows reuse in different contexts.
#7. Things that change at different rates change for different reasons.
Some nuggets I liked in the book:
Nugget #1 : If you think of a class as having a single purpose, then the things it does are what it allows it to fulfill that purpose.
Nugget #2 : Public methods should read like a description of responsibilities. The public interface is a contract that articulates the responsibilities of your class.
Nugget #3 : Seeking Context Independence. The best possible situation is for an object to be completely independent of its context. An object that could collaborate with others without knowing who they are or what they do.
Find out what is running on a given port
1. Find out what is running on a given port
$sudo lsof -i :4567
Password:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 86461 zepho 9u IPv6 0xffffff803ac28f80 0t0 TCP localhost:tram (LISTEN)
ruby 86461 zepho 10u IPv4 0xffffff8022e51c00 0t0 TCP localhost:tram (LISTEN)
ruby 86461 zepho 11u IPv6 0xffffff802197bac0 0t0 TCP localhost:tram (LISTEN)
2. Check what process is running with that process id.
$ ps aux | grep 86461
zepho 86461 0.0 0.1 2492352 18280 s005 T 4:59PM 0:00.31 ruby hello.rb
zepho 91001 0.0 0.0 2434892 460 s005 R+ 8:37PM 0:00.00 grep 86461
3. Kill that mother fucker like this:
$ kill -9 86461
Top 6 Ruby Links for the week May 21, 2015
1. Best Post of the Week : The Ruby Community: The Next Version
2. Most Useful Library of the Week : An intelligent pure Ruby WHOIS client and parser.
3. A good Alternative to Nokogiri
4. How to Write Faster Ruby
5. Dynamic Site as fast as a Static Generated One with Raptor : Interesting article. I would do not do it. I don't need a dynamic site mixed with static static, if I need a static site, I use Python to deploy it to GAE. Essential TDD Tutorial site is deployed this way.
6. Rails 5 - Much Faster Collection Rendering
2. Most Useful Library of the Week : An intelligent pure Ruby WHOIS client and parser.
3. A good Alternative to Nokogiri
4. How to Write Faster Ruby
5. Dynamic Site as fast as a Static Generated One with Raptor : Interesting article. I would do not do it. I don't need a dynamic site mixed with static static, if I need a static site, I use Python to deploy it to GAE. Essential TDD Tutorial site is deployed this way.
6. Rails 5 - Much Faster Collection Rendering
Wednesday, May 27, 2015
Setting Up Port Forwarding in VirtualBox
1) If the VM is running, stop it.
2) To forward from port 3001 on the host to port 3000 on the guest, run the following command on the host.
$ VBoxManage modifyvm "Ubuntu" --natpf1 "webrick,tcp,,3001,,3000"
3) To delete the port forwarding run:
VBoxManage modifyvm "Ubuntu" --natpf1 delete "webrick"
4) Now you can go to http://localhost:3001 on your host to hit webrick running on your VM.
The page loads very slow. Is there any way to speed it up?
2) To forward from port 3001 on the host to port 3000 on the guest, run the following command on the host.
$ VBoxManage modifyvm "Ubuntu" --natpf1 "webrick,tcp,,3001,,3000"
3) To delete the port forwarding run:
VBoxManage modifyvm "Ubuntu" --natpf1 delete "webrick"
4) Now you can go to http://localhost:3001 on your host to hit webrick running on your VM.
The page loads very slow. Is there any way to speed it up?
Tuesday, May 19, 2015
** WARNING: soft rlimits too low. Number of files is 256, should be at least 1000
Running mongodb in Mac OS 10.10.3 can give that warning. If this warning is ignored, it will lead to problems. In the same terminal,run :
$ulimit -n 1024
$ mongod --config /usr/local/etc/mongod.conf
Thursday, May 07, 2015
MOPED: Could not resolve IP for: xyz:27017 runtime: n/a
Could not connect to a primary node for replica set #]>
Moped::Errors::ConnectionFailure:
The following error can happen if the xyz is not localhost. If you are running the mongo on localhost on your machine, change the mongoid.yml file to point to localhost. This will fix the problem.
Friday, April 24, 2015
NoMethodError: undefined method `devise' for User
Problem: NoMethodError: undefined method `devise' for User (call 'User.connection' to establish a connection):Class
Solution:
run rake db:migrate
before :
rails g devise user
Solution:
run rake db:migrate
before :
rails g devise user
Thursday, April 23, 2015
Upgrading Ruby using rbenv
1. Change the default version of Ruby globally to use 2.2.2
rbenv global 2.2.2
2. Change the ruby version in Gemfile
ruby '2.2.2'
3. gem install bundler
4. bundle
rbenv global 2.2.2
2. Change the ruby version in Gemfile
ruby '2.2.2'
3. gem install bundler
4. bundle
Wednesday, April 22, 2015
Sinatra Console
There is nothing similar to rails console in sinatra. You can go to irb and do a :
require './myapp.rb'
to start experimenting with your Sinatra app.
You can create a console.rb and put the following code:
require './game.rb'
require 'irb'
ARGV.clear
IRB.start
You now have a simple Sinatra console, you can run it as ruby console.rb.
Reference:
Sinatra Console
require './myapp.rb'
to start experimenting with your Sinatra app.
You can create a console.rb and put the following code:
require './game.rb'
require 'irb'
ARGV.clear
IRB.start
You now have a simple Sinatra console, you can run it as ruby console.rb.
Reference:
Sinatra Console
irb history
I installed ruby 2.2.1 using rbenv on Mac OS 10.10.3. By default the irb console does not save the history, so you cannot use the saved code in the history by using the arrows in new irb sessions. To fix this problem, create ~/.irbrc and add this code:
require 'irb/ext/save-history'
#History configuration
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"
require 'irb/ext/save-history'
#History configuration
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"
Tuesday, April 21, 2015
Bundler is using a binstub that was created for a different gem.
This is an rvm issue. Suggestions on rvm home page did not work. Solution: Uninstall rvm and use rbenv to manage ruby versions.
Add the following to ~/.bashrc
[[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Load the default .profile
rt PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"
source ~/.bashrc
Say 'Yes' to the prompt.
which bundle showed no output. Run: gem install bundle
References:
https://gorails.com/forum/rbenv-bundle-command-not-found
https://gorails.com/setup/osx/10.10-yosemite
Add the following to ~/.bashrc
[[ -s "$HOME/.profile" ]] && source "$HOME/.profile" # Load the default .profile
rt PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"
source ~/.bashrc
Say 'Yes' to the prompt.
which bundle showed no output. Run: gem install bundle
References:
https://gorails.com/forum/rbenv-bundle-command-not-found
https://gorails.com/setup/osx/10.10-yosemite
Monday, April 20, 2015
Textmate 2 Setup Mate
You may get No such file or directory error when you create the symlink.
1. Run:
ln -s /Applications/TextMate.app/Contents/SharedSupport/Support/bin/mate /usr/local/bin/mate
2. Go to Textmate -> Preferences, click on Terminal tab, click install for 'Shell support'.
Now the mate command will work.
Tuesday, April 14, 2015
short prompt in ubuntu 14.04 terminal
In your ~/.bash_profile add:
PROMPT_COMMAND='PS1="[\W]\\$ "'
Open a new terminal and you should see a small prompt.
PROMPT_COMMAND='PS1="[\W]\\$ "'
Open a new terminal and you should see a small prompt.
Saturday, April 11, 2015
Using Custom Fonts in Rails 4.2
1. For Rails 4.2, copy the custom fonts to the folder app/assets/fonts. I am using the purchased fonts OpenSans.
2. Declare your font in your css file like this:
@font-face {
font-family: 'OpenSans-Bold';
src:url('OpenSans-Bold.ttf');
}
3. Use the declared font in css. For example:
font-family: 'OpenSans-Regular'
4. Add gem 'font-awesome-sass' to Gemfile
5. Run bundle intall
6. In application.scss, add:
@import "font-awesome-sprockets";
@import "font-awesome";
2. Declare your font in your css file like this:
@font-face {
font-family: 'OpenSans-Bold';
src:url('OpenSans-Bold.ttf');
}
3. Use the declared font in css. For example:
font-family: 'OpenSans-Regular'
4. Add gem 'font-awesome-sass' to Gemfile
5. Run bundle intall
6. In application.scss, add:
@import "font-awesome-sprockets";
@import "font-awesome";
Sunday, April 05, 2015
Using Jeweler to Create Ruby Gems
1. gem install jeweler
2. jeweler gem-name
3. bundle install
4. rake version:write MAJOR=0 MINOR=1 PATCH=0
5. git remote rm origin
Jeweler automatically creates a git repo
6. Open the Rakefile and customize the gem details.
I changed the default github repo URL to bitbucket repo URL
7. git remote add origin bitbucket-url
8. Delete the line Jeweler::RubygemsDotOrgTasks.new to prevent accidental release to Gemcutter.
9. rake gemspec
10. rake build to create the .gem file that can be used with any project.
2. jeweler gem-name
3. bundle install
4. rake version:write MAJOR=0 MINOR=1 PATCH=0
5. git remote rm origin
Jeweler automatically creates a git repo
6. Open the Rakefile and customize the gem details.
I changed the default github repo URL to bitbucket repo URL
7. git remote add origin bitbucket-url
8. Delete the line Jeweler::RubygemsDotOrgTasks.new to prevent accidental release to Gemcutter.
9. rake gemspec
10. rake build to create the .gem file that can be used with any project.
pessimistic dependency may be overly strict
ISSUE
$rake build
WARNING: pessimistic dependency on jeweler (~> 2.0.1, development) may be overly strict
if jeweler is semantically versioned, use:
add_development_dependency 'jeweler', '~> 2.0', '>= 2.0.1'
WARNING: See http://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: pdf_stamper
Version: 0.2.0
File: pdf_stamper-0.2.0.gem
RESOLUTION
group :development do
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0"
gem "jeweler", "~> 2.0"
end
Now you can build the gem file:
$rm -rf pkg
$rake build
Successfully built RubyGem
Name: pdf_stamper
Version: 0.2.0
File: pdf_stamper-0.2.0.gem
$rake build
WARNING: pessimistic dependency on jeweler (~> 2.0.1, development) may be overly strict
if jeweler is semantically versioned, use:
add_development_dependency 'jeweler', '~> 2.0', '>= 2.0.1'
WARNING: See http://guides.rubygems.org/specification-reference/ for help
Successfully built RubyGem
Name: pdf_stamper
Version: 0.2.0
File: pdf_stamper-0.2.0.gem
RESOLUTION
group :development do
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0"
gem "jeweler", "~> 2.0"
end
Now you can build the gem file:
$rm -rf pkg
$rake build
Successfully built RubyGem
Name: pdf_stamper
Version: 0.2.0
File: pdf_stamper-0.2.0.gem
Saturday, April 04, 2015
Twitter Bootstrap 3.3.4 on Rails 4.2.1
1. Add : gem 'bootstrap-sass', '~> 3.3.4' to Gemfile.
2. Run bundle
3. Rename application.css to application.scss
4. Copy this to application.scss
// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
@import "bootstrap-sprockets";
@import "bootstrap";
2. Run bundle
3. Rename application.css to application.scss
4. Copy this to application.scss
// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
@import "bootstrap-sprockets";
@import "bootstrap";
Sunday, March 29, 2015
Client Side Validations Gems vs JQuery Libray in a Rails project
Client side validations gem has the following issues:
1. Browser compatibility is not known.
2. Radio buttons issue.
3. Document is not up to date for Rails 3.2.
4. Depends on persistence mechanism. Supports Mongoid, MongoMapper.
5. Custom validations still require writing javascripts.
Advantages of pure jQuery library approach:
1. Clean separation of UI logic from Mid-tier and Persistence tier.
2. Front-end developers can develop and test without any server-side coding. Faster.
3. Wide browser compatibility.
4. Upgrades are easier and not affected by Rails and Client Side Validation gem versions.
5. Simplicity. Rule based and less code to write, integrate, test and maintain.
1. Browser compatibility is not known.
2. Radio buttons issue.
3. Document is not up to date for Rails 3.2.
4. Depends on persistence mechanism. Supports Mongoid, MongoMapper.
5. Custom validations still require writing javascripts.
Advantages of pure jQuery library approach:
1. Clean separation of UI logic from Mid-tier and Persistence tier.
2. Front-end developers can develop and test without any server-side coding. Faster.
3. Wide browser compatibility.
4. Upgrades are easier and not affected by Rails and Client Side Validation gem versions.
5. Simplicity. Rule based and less code to write, integrate, test and maintain.
dyld: Library not loaded error
Upgrading rvm using : rvm get head
seems to create problems with the error:
dyld: Library not loaded: /usr/local/lib/libruby.1.9.1.dylib
Referenced from: /usr/local/bin/ruby
Reason: image not found
Trace/BPT trap: 5
I had to do: rvm get stable
and use Ruby version 2.1.5
to get past that error.
seems to create problems with the error:
dyld: Library not loaded: /usr/local/lib/libruby.1.9.1.dylib
Referenced from: /usr/local/bin/ruby
Reason: image not found
Trace/BPT trap: 5
I had to do: rvm get stable
and use Ruby version 2.1.5
to get past that error.
The Scientific Method is Crap : Teman Cooke at TED
Great presentation explaining why it is Crap. He is right. How do you explain discoveries that were made by accident? Instead of the Scientific Method, we can adopt:
Cycle of Scientific Thinking
Observations
Questions
Model (Hypothesis)
Prediction
Testing / Checking
Answers
Cycle of Scientific Thinking
Observations
Questions
Model (Hypothesis)
Prediction
Testing / Checking
Answers
Friday, February 27, 2015
How to export specific columns in a table to a csv file in mysql
Go to the mysql prompt as usual and run the command:
select id, email from users INTO OUTFILE '/Users/zepho/temp/users.csv' FIELDS TERMINATED BY ',';
This will create a csv file with only id, email columns in the users table in the users.csv file.
ERROR 1 (HY000): Can't create/write to file '/var/empty/projects/gold' (Errcode: 2)
ERROR 1 (HY000): Can't create/write to file '/Users/zepho/temp/users.csv' (Errcode: 13)
If you get these errors run:
chmod 777 /Users/zepho/temp
select id, email from users INTO OUTFILE '/Users/zepho/temp/users.csv' FIELDS TERMINATED BY ',';
This will create a csv file with only id, email columns in the users table in the users.csv file.
ERROR 1 (HY000): Can't create/write to file '/var/empty/projects/gold' (Errcode: 2)
ERROR 1 (HY000): Can't create/write to file '/Users/zepho/temp/users.csv' (Errcode: 13)
If you get these errors run:
chmod 777 /Users/zepho/temp
Thursday, February 26, 2015
How to turn off Spring
Spring is a big headache in development environment. Creates weird issues like not being able to play in rails console and is a big waste of time. To turn off spring, in the terminal, run:
export DISABLE_SPRING=1
You will now be able to go to rails console. You may also have to kill any stray rails
console processes that may be running but never succeeded.
To remove it :
- 'Unspring' your bin/ executables:
bin/spring binstub --remove --all - Remove spring from your Gemfile
Saturday, February 21, 2015
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) Mac OS 10.9.5
I was able to connect to the server using SQL Pro but not from the command line. The solution:
$ mysql -h 127.0.0.1 -P 3306 -u root -p
You can also use telnet to check the connectivity:
$telnet 127.0.0.1 3306
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
J
5.6.21 81/8j0O?Am$fZn<||}~!mysql_native_password
!#08S01Got packets out of orderConnection closed by foreign host.
Friday, February 20, 2015
Is TDD Dead Part 3 Transcript Concise Version : Fast Feedback and Quality Assurance
Kent said that decisions involving TDD were about trade-offs: "In some ideal world we would have instant, infallible feedback about our programming decisions", "every key stroke that I make, if the code is ready to deploy, it would just instantly deploy." But that ideal is impossible at the moment so the question is how far do we back off from that. He went to enumerate several constraints in the trade-off.
Those four are the constraints he thinks we need to compare. "My personal goal is just to understand the set of trade-offs by articulating them to people who are prepared to tear my ideas apart in a constructive way"
Fowler outlined three things that we can look at, to get feedback on:
David introduced the topic that TDD's success had led to a neglect of QA. The other issue is that to understand trade-offs you have to understand the costs, all the talk of TDD has been on the benefits. This neglect of costs is why people cannot comprehend that there is such a thing as test-induced damage. The trade-off continuum is true of other things. Consider the cost of reliability: going from 99% to 99.999% is exponentially more expensive than getting to 99%. We must also consider criticality. High reliability is important for space shuttles and pacemakers, but wrong for an exploratory web site. The rule of not writing a line of production code without a test doesn't fit in with trade-offs around criticality.
David agreed that it was good to mindfully trade-off QA for initial speed, but some have taken programmer testing too far and don't see the value of exploratory testing. Your tests may be green but when it's in production users do things you don't expect.
David says that worst of all is when developers are not part of of customer service. Many programmers don't want to be on-call because it's drudgery, but it's also a feedback loop. Code with green tests can be a plateau that's below where you want to be. "The on-call is the feedback loop that teaches you what tests you didn't write." As soon as you think you don't make mistakes any more, that's a mistake, and you stop growing. He'd rather pay the price of catching that early with a phone call at 2am.
- Frequency: how rapidly do we want our feedback ?
- Fidelity: how accurate do we want the red/green signal to be?
- Overhead: how much are we prepared to pay?
- Lifespan: how long is this software going to be around, which is a probability as well as time.
Those four are the constraints he thinks we need to compare. "My personal goal is just to understand the set of trade-offs by articulating them to people who are prepared to tear my ideas apart in a constructive way"
Fowler outlined three things that we can look at, to get feedback on:
- Is the software doing something useful for the user of the software?
- Have I broken anything?
- Is my code-base healthy? This so I can continue to build things quickly.
David introduced the topic that TDD's success had led to a neglect of QA. The other issue is that to understand trade-offs you have to understand the costs, all the talk of TDD has been on the benefits. This neglect of costs is why people cannot comprehend that there is such a thing as test-induced damage. The trade-off continuum is true of other things. Consider the cost of reliability: going from 99% to 99.999% is exponentially more expensive than getting to 99%. We must also consider criticality. High reliability is important for space shuttles and pacemakers, but wrong for an exploratory web site. The rule of not writing a line of production code without a test doesn't fit in with trade-offs around criticality.
David agreed that it was good to mindfully trade-off QA for initial speed, but some have taken programmer testing too far and don't see the value of exploratory testing. Your tests may be green but when it's in production users do things you don't expect.
David says that worst of all is when developers are not part of of customer service. Many programmers don't want to be on-call because it's drudgery, but it's also a feedback loop. Code with green tests can be a plateau that's below where you want to be. "The on-call is the feedback loop that teaches you what tests you didn't write." As soon as you think you don't make mistakes any more, that's a mistake, and you stop growing. He'd rather pay the price of catching that early with a phone call at 2am.
How to use Favicon for your Rails 4.2 app
1. Copy your favicon.ico to app/assets/images folder.
2. In the layouts/application.html.erb add: <%= favicon_link_tag %> within the head tags.
3. Deploy and enjoy!
2. In the layouts/application.html.erb add: <%= favicon_link_tag %> within the head tags.
3. Deploy and enjoy!
Monday, February 16, 2015
Disabling SSL V3 for Poodle for Apache in Ubuntu
1. edit /etc/apache2/mods-available/ssl.conf
2. Look for : SSLProtocol All -SSLv2
3. Replace it with : SSLProtocol All -SSLv2 -SSLv3
4. Test configuration: apachectl configtest
5. Restart Apache : sudo service apache2 restart
2. Look for : SSLProtocol All -SSLv2
3. Replace it with : SSLProtocol All -SSLv2 -SSLv3
4. Test configuration: apachectl configtest
5. Restart Apache : sudo service apache2 restart
Saturday, February 14, 2015
Auto Refresh Browser on File Save
I was looking for a tool that reloads static html pages automatically on file save. CodeKit does not work on Mac 10.7.5 and it costs $40. Here is a simple alternative.
1. Install Auto Reload Firefox Plugin
2. Go to Tools -> AutoReload Preferences and turn off notifications. It's a bit distracting.
3. Open the local html file in a text editor.
Now, whenever you save the file, the page will get refreshed automatically. Much faster feedback. I love it.
1. Install Auto Reload Firefox Plugin
2. Go to Tools -> AutoReload Preferences and turn off notifications. It's a bit distracting.
3. Open the local html file in a text editor.
Now, whenever you save the file, the page will get refreshed automatically. Much faster feedback. I love it.
Sunday, February 08, 2015
How to build codeschool.com clone and make $35 million in 4 years!
1. You need Ubuntu 14.04 LTS. I installed it on my $10/month Linode instance. Digital Ocean offers $5/month plan which is good enough.
2. Expose docker to access over network
3. From your machine: $
ssh root@ip-address-of-your-server
4. $chmod 777 setup-script.sh
$sh setup-script.sh
5. git clone git@github.com:grounds/grounds.io.git
6. cd grounds.io
7. make pull
8. In ~/.profile add export DOCKER_URL=http://ip-address-of-your-server:4243
9. chmod -R 777 grounds.io
10. Edit fig.yml:
web:
build: .
command: rake run
ports:
- '80:3000'
11. Run the Rails app:
RAILS_ENV=production SECRET_KEY_BASE="your secret key generated using rake secret" fig up -d
2. Expose docker to access over network
3. From your machine: $
ssh root@ip-address-of-your-server
4. $chmod 777 setup-script.sh
$sh setup-script.sh
5. git clone git@github.com:grounds/grounds.io.git
6. cd grounds.io
7. make pull
8. In ~/.profile add export DOCKER_URL=http://ip-address-of-your-server:4243
9. chmod -R 777 grounds.io
10. Edit fig.yml:
web:
build: .
command: rake run
ports:
- '80:3000'
11. Run the Rails app:
RAILS_ENV=production SECRET_KEY_BASE="your secret key generated using rake secret" fig up -d
See it in action at www.rubyplus.biz
Friday, February 06, 2015
Is TDD Dead Concise Version : Feedback and QA
Kent said that decisions when doing TDD is about trade-offs, "In some ideal world we would have instant, infallible feedback about our programming decisions"… "every key stroke that I make, if the code is ready to deploy, it would just instantly deploy." He went to enumerate several constraints in the trade-off.
Frequency: how rapidly do we want our feedback ?
Fidelity: how accurate do we want the red/green signal to be?
Overhead: how much are we prepared to pay?
Lifespan: how long is this software going to be around, which is probability as well as time.
Martin Fowler outlined three things we can look at to get feedback on:
The other issue is that to understand trade-offs you have to understand the costs, all the talk of TDD has been on the benefits. This neglect of costs is why people cannot comprehend that there is such a thing as test-induced damage. The trade-off continuum is true of other things. Consider the cost of reliability: going from 99% to 99.999% is exponentially more expensive than getting to 99%. We must also consider criticality. High reliability is important for space shuttles and pacemakers, but wrong for an exploratory web site. The rule of not writing a line of production code without a test doesn't fit in with trade-offs around criticality.
David agreed that it was good to mindfully trade-off QA for initial speed, but some have taken programmer testing too far and don't see the value of exploratory testing. If developers think they can create high-enough quality software without QA they are wrong, your tests may be green but when it's in production users do things you don't expect.
Programmers on-call is also a feedback loop. Kent said: "The on-call is the feedback loop that teaches you what tests you didn't write."
Reference:
Is TDD Dead? Video
Is TDD Dead? Transcript
Frequency: how rapidly do we want our feedback ?
Fidelity: how accurate do we want the red/green signal to be?
Overhead: how much are we prepared to pay?
Lifespan: how long is this software going to be around, which is probability as well as time.
Martin Fowler outlined three things we can look at to get feedback on:
- Is the software doing something useful for the user of the software?
- Have I broken anything? I want to see every test fail at least once.
- Is my code-base healthy? So that I can continue to build things quickly.
The other issue is that to understand trade-offs you have to understand the costs, all the talk of TDD has been on the benefits. This neglect of costs is why people cannot comprehend that there is such a thing as test-induced damage. The trade-off continuum is true of other things. Consider the cost of reliability: going from 99% to 99.999% is exponentially more expensive than getting to 99%. We must also consider criticality. High reliability is important for space shuttles and pacemakers, but wrong for an exploratory web site. The rule of not writing a line of production code without a test doesn't fit in with trade-offs around criticality.
David agreed that it was good to mindfully trade-off QA for initial speed, but some have taken programmer testing too far and don't see the value of exploratory testing. If developers think they can create high-enough quality software without QA they are wrong, your tests may be green but when it's in production users do things you don't expect.
Programmers on-call is also a feedback loop. Kent said: "The on-call is the feedback loop that teaches you what tests you didn't write."
Reference:
Is TDD Dead? Video
Is TDD Dead? Transcript
Wednesday, February 04, 2015
TDD is Dead - Part 2 Concise Version
Can TDD lead to design damage?
This entire debate would not have occurred if DHH had read this quote by Matsuo Basho:
Kent said that developers' make one design decision at a time. TDD puts an evolutionary pressure on a design, people have different preferences for the grain-size of how much is covered by their tests. David replied that there's a direct correlation between the size of code and how easy it is to change it.
David said the reason people wanted isolation was due to TDD. You can't just swap out an in-memory store for a call to a web service because they have different operational characteristics. These swap-ability pipe-dreams aren't the real goal - the real goal is isolated testing. Kent agreed that you can't treat in-memory and web services the same as the failure cases are different. The boundaries between elements will leak to some degree "the question is how much are we willing to spend to get how much decoupling between elements".
Kent saw the difference between 10 lines of code and 60 as a cohesion issue. David agreed but argued that cohesion and coupling are often opposed. Higher coupling is usually worth the price to get better cohesion. Kent observed that there are other ways to eliminate external dependencies, you can also use intermediate results, this is what happens with compilers.
Something that's hard to test is an indication that you need a design insight, it's often useful to get up and take a walk to find those insights that lead to better designs that are also more testable.
Kent clarified he wasn't talking about TDD, but about software design in general, it's not about TDD it's about how to get feedback. Thinking about software design is the thing, because it pays off so big when you get a good design insight. Getting these insights isn't about your workflow, it's about things like knowing when to work and when to rest, gathering influences from other places, collaborating with other people.
This entire debate would not have occurred if DHH had read this quote by Matsuo Basho:
Do not seek to follow in the footsteps of the wise. Seek what they sought.
David's objections:
- Unnecessary indirection and complexity required to make it easier to test in isolation.
- Using mocks to isolate from external dependencies
The design David showed wasn't due to TDD, the real issue is that these indirections are all good tricks under some circumstances and we need to understand whether they are worth the cost or not.
Kent said that developers' make one design decision at a time. TDD puts an evolutionary pressure on a design, people have different preferences for the grain-size of how much is covered by their tests. David replied that there's a direct correlation between the size of code and how easy it is to change it.
David said the reason people wanted isolation was due to TDD. You can't just swap out an in-memory store for a call to a web service because they have different operational characteristics. These swap-ability pipe-dreams aren't the real goal - the real goal is isolated testing. Kent agreed that you can't treat in-memory and web services the same as the failure cases are different. The boundaries between elements will leak to some degree "the question is how much are we willing to spend to get how much decoupling between elements".
Kent saw the difference between 10 lines of code and 60 as a cohesion issue. David agreed but argued that cohesion and coupling are often opposed. Higher coupling is usually worth the price to get better cohesion. Kent observed that there are other ways to eliminate external dependencies, you can also use intermediate results, this is what happens with compilers.
Something that's hard to test is an indication that you need a design insight, it's often useful to get up and take a walk to find those insights that lead to better designs that are also more testable.
Kent clarified he wasn't talking about TDD, but about software design in general, it's not about TDD it's about how to get feedback. Thinking about software design is the thing, because it pays off so big when you get a good design insight. Getting these insights isn't about your workflow, it's about things like knowing when to work and when to rest, gathering influences from other places, collaborating with other people.
Executive Summary
DHH is not seeking what Kent Beck is after:
- Fast Feedback Loop
- Cheap Way to Test Ideas
- Gaining Confidence
Reference
Saturday, January 31, 2015
Deploying Static Sites on Google App Engine
Why Google App Engine?
1. Hosted on Google infrastructure, so it's going to be fast.
2. If it's a low traffic site, then it's almost free.
Steps
1. Python 2.7 must be installed on your machine. If you are on Mac, it's already installed.
2. Download GAE SDK for Python.
3. Create new application for your static site using GoogleAppEngineLauncher.
4. Create a directory called static under your-site-name directory.
5. Copy the following sample app.yaml for a static site:
application: essentialtdd
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: /(.*\.(appcache|manifest))
mime_type: text/cache-manifest
static_files: static/\1
upload: static/(.*\.(appcache|manifest))
expiration: "0m"
- url: /(.*\.atom)
mime_type: application/atom+xml
static_files: static/\1
upload: static/(.*\.atom)
expiration: "1h"
- url: /(.*\.crx)
mime_type: application/x-chrome-extension
static_files: static/\1
upload: static/(.*\.crx)
- url: /(.*\.css)
mime_type: text/css
static_files: static/\1
upload: static/(.*\.css)
- url: /(.*\.eot)
mime_type: application/vnd.ms-fontobject
static_files: static/\1
upload: static/(.*\.eot)
- url: /(.*\.htc)
mime_type: text/x-component
static_files: static/\1
upload: static/(.*\.htc)
- url: /(.*\.html)
mime_type: text/html
static_files: static/\1
upload: static/(.*\.html)
expiration: "1h"
- url: /(.*\.ico)
mime_type: image/x-icon
static_files: static/\1
upload: static/(.*\.ico)
expiration: "7d"
- url: /(.*\.js)
mime_type: text/javascript
static_files: static/\1
upload: static/(.*\.js)
- url: /(.*\.json)
mime_type: application/json
static_files: static/\1
upload: static/(.*\.json)
expiration: "1h"
- url: /(.*\.m4v)
mime_type: video/m4v
static_files: static/\1
upload: static/(.*\.m4v)
- url: /(.*\.mp4)
mime_type: video/mp4
static_files: static/\1
upload: static/(.*\.mp4)
- url: /(.*\.(ogg|oga))
mime_type: audio/ogg
static_files: static/\1
upload: static/(.*\.(ogg|oga))
- url: /(.*\.ogv)
mime_type: video/ogg
static_files: static/\1
upload: static/(.*\.ogv)
- url: /(.*\.otf)
mime_type: font/opentype
static_files: static/\1
upload: static/(.*\.otf)
- url: /(.*\.rss)
mime_type: application/rss+xml
static_files: static/\1
upload: static/(.*\.rss)
expiration: "1h"
- url: /(.*\.safariextz)
mime_type: application/octet-stream
static_files: static/\1
upload: static/(.*\.safariextz)
- url: /(.*\.(svg|svgz))
mime_type: images/svg+xml
static_files: static/\1
upload: static/(.*\.(svg|svgz))
- url: /(.*\.swf)
mime_type: application/x-shockwave-flash
static_files: static/\1
upload: static/(.*\.swf)
- url: /(.*\.ttf)
mime_type: font/truetype
static_files: static/\1
upload: static/(.*\.ttf)
- url: /(.*\.txt)
mime_type: text/plain
static_files: static/\1
upload: static/(.*\.txt)
- url: /(.*\.unity3d)
mime_type: application/vnd.unity
static_files: static/\1
upload: static/(.*\.unity3d)
- url: /(.*\.webm)
mime_type: video/webm
static_files: static/\1
upload: static/(.*\.webm)
- url: /(.*\.webp)
mime_type: image/webp
static_files: static/\1
upload: static/(.*\.webp)
- url: /(.*\.woff)
mime_type: application/x-font-woff
static_files: static/\1
upload: static/(.*\.woff)
- url: /(.*\.xml)
mime_type: application/xml
static_files: static/\1
upload: static/(.*\.xml)
expiration: "1h"
- url: /(.*\.xpi)
mime_type: application/x-xpinstall
static_files: static/\1
upload: static/(.*\.xpi)
# image files
- url: /(.*\.(bmp|gif|ico|jpeg|jpg|png))
static_files: static/\1
upload: static/(.*\.(bmp|gif|ico|jpeg|jpg|png))
# audio files
- url: /(.*\.(mid|midi|mp3|wav))
static_files: static/\1
upload: static/(.*\.(mid|midi|mp3|wav))
# windows files
- url: /(.*\.(doc|exe|ppt|rtf|xls))
static_files: static/\1
upload: static/(.*\.(doc|exe|ppt|rtf|xls))
# compressed files
- url: /(.*\.(bz2|gz|rar|tar|tgz|zip))
static_files: static/\1
upload: static/(.*\.(bz2|gz|rar|tar|tgz|zip))
# index files
- url: /(.+)/
static_files: static/\1/index.html
upload: static/(.+)/index.html
expiration: "15m"
- url: /(.+)
static_files: static/\1/index.html
upload: static/(.+)/index.html
expiration: "15m"
# site root
- url: /
static_files: static/index.html
upload: static/index.html
expiration: "15m"
6. Click deploy on GoogleAppEngineLauncher.
Since I bought my domain using Google domains, I configured custom domain to point to my GAE instance by using the Google Developer Console and Google Domains account page as follows.
References
1. Free Static Website Hosting on Google App Engine
2. Google App Engine to Host a Static Site
3. Google App Engine Concole
4. Configuration file
1. Hosted on Google infrastructure, so it's going to be fast.
2. If it's a low traffic site, then it's almost free.
Steps
1. Python 2.7 must be installed on your machine. If you are on Mac, it's already installed.
2. Download GAE SDK for Python.
3. Create new application for your static site using GoogleAppEngineLauncher.
4. Create a directory called static under your-site-name directory.
5. Copy the following sample app.yaml for a static site:
application: essentialtdd
version: 1
runtime: python27
api_version: 1
threadsafe: yes
handlers:
- url: /(.*\.(appcache|manifest))
mime_type: text/cache-manifest
static_files: static/\1
upload: static/(.*\.(appcache|manifest))
expiration: "0m"
- url: /(.*\.atom)
mime_type: application/atom+xml
static_files: static/\1
upload: static/(.*\.atom)
expiration: "1h"
- url: /(.*\.crx)
mime_type: application/x-chrome-extension
static_files: static/\1
upload: static/(.*\.crx)
- url: /(.*\.css)
mime_type: text/css
static_files: static/\1
upload: static/(.*\.css)
- url: /(.*\.eot)
mime_type: application/vnd.ms-fontobject
static_files: static/\1
upload: static/(.*\.eot)
- url: /(.*\.htc)
mime_type: text/x-component
static_files: static/\1
upload: static/(.*\.htc)
- url: /(.*\.html)
mime_type: text/html
static_files: static/\1
upload: static/(.*\.html)
expiration: "1h"
- url: /(.*\.ico)
mime_type: image/x-icon
static_files: static/\1
upload: static/(.*\.ico)
expiration: "7d"
- url: /(.*\.js)
mime_type: text/javascript
static_files: static/\1
upload: static/(.*\.js)
- url: /(.*\.json)
mime_type: application/json
static_files: static/\1
upload: static/(.*\.json)
expiration: "1h"
- url: /(.*\.m4v)
mime_type: video/m4v
static_files: static/\1
upload: static/(.*\.m4v)
- url: /(.*\.mp4)
mime_type: video/mp4
static_files: static/\1
upload: static/(.*\.mp4)
- url: /(.*\.(ogg|oga))
mime_type: audio/ogg
static_files: static/\1
upload: static/(.*\.(ogg|oga))
- url: /(.*\.ogv)
mime_type: video/ogg
static_files: static/\1
upload: static/(.*\.ogv)
- url: /(.*\.otf)
mime_type: font/opentype
static_files: static/\1
upload: static/(.*\.otf)
- url: /(.*\.rss)
mime_type: application/rss+xml
static_files: static/\1
upload: static/(.*\.rss)
expiration: "1h"
- url: /(.*\.safariextz)
mime_type: application/octet-stream
static_files: static/\1
upload: static/(.*\.safariextz)
- url: /(.*\.(svg|svgz))
mime_type: images/svg+xml
static_files: static/\1
upload: static/(.*\.(svg|svgz))
- url: /(.*\.swf)
mime_type: application/x-shockwave-flash
static_files: static/\1
upload: static/(.*\.swf)
- url: /(.*\.ttf)
mime_type: font/truetype
static_files: static/\1
upload: static/(.*\.ttf)
- url: /(.*\.txt)
mime_type: text/plain
static_files: static/\1
upload: static/(.*\.txt)
- url: /(.*\.unity3d)
mime_type: application/vnd.unity
static_files: static/\1
upload: static/(.*\.unity3d)
- url: /(.*\.webm)
mime_type: video/webm
static_files: static/\1
upload: static/(.*\.webm)
- url: /(.*\.webp)
mime_type: image/webp
static_files: static/\1
upload: static/(.*\.webp)
- url: /(.*\.woff)
mime_type: application/x-font-woff
static_files: static/\1
upload: static/(.*\.woff)
- url: /(.*\.xml)
mime_type: application/xml
static_files: static/\1
upload: static/(.*\.xml)
expiration: "1h"
- url: /(.*\.xpi)
mime_type: application/x-xpinstall
static_files: static/\1
upload: static/(.*\.xpi)
# image files
- url: /(.*\.(bmp|gif|ico|jpeg|jpg|png))
static_files: static/\1
upload: static/(.*\.(bmp|gif|ico|jpeg|jpg|png))
# audio files
- url: /(.*\.(mid|midi|mp3|wav))
static_files: static/\1
upload: static/(.*\.(mid|midi|mp3|wav))
# windows files
- url: /(.*\.(doc|exe|ppt|rtf|xls))
static_files: static/\1
upload: static/(.*\.(doc|exe|ppt|rtf|xls))
# compressed files
- url: /(.*\.(bz2|gz|rar|tar|tgz|zip))
static_files: static/\1
upload: static/(.*\.(bz2|gz|rar|tar|tgz|zip))
# index files
- url: /(.+)/
static_files: static/\1/index.html
upload: static/(.+)/index.html
expiration: "15m"
- url: /(.+)
static_files: static/\1/index.html
upload: static/(.+)/index.html
expiration: "15m"
# site root
- url: /
static_files: static/index.html
upload: static/index.html
expiration: "15m"
6. Click deploy on GoogleAppEngineLauncher.
Since I bought my domain using Google domains, I configured custom domain to point to my GAE instance by using the Google Developer Console and Google Domains account page as follows.
References
1. Free Static Website Hosting on Google App Engine
2. Google App Engine to Host a Static Site
3. Google App Engine Concole
4. Configuration file
Friday, January 30, 2015
Explicit Use Case Representation in Rails Apps
Here is the notes from my Silicon Valley Ruby presentation:
Opening
Object Oriented Programming promised us re-use and ease of maintenance. OO paradigm delivered on re-use but not on ease of maintenance. Hi, I am Uncle Toni, the rest of the presentation is about how we can overcome the limitation of Object-Oriented Paradigm.
Middle
Ease of maintenance? How? It is relative. When compared to procedural languages, yes. But, this is 2015. We need to be able to quantify the ease of maintenance claim. Given a requirement, can we estimate and come up with how many weeks it will take to finish? Your manager comes to you and asks how long a new feature will take, how do you answer that question?
Opening
Object Oriented Programming promised us re-use and ease of maintenance. OO paradigm delivered on re-use but not on ease of maintenance. Hi, I am Uncle Toni, the rest of the presentation is about how we can overcome the limitation of Object-Oriented Paradigm.
Middle
Ease of maintenance? How? It is relative. When compared to procedural languages, yes. But, this is 2015. We need to be able to quantify the ease of maintenance claim. Given a requirement, can we estimate and come up with how many weeks it will take to finish? Your manager comes to you and asks how long a new feature will take, how do you answer that question?
What do you do to find out the level of effort required to finish the feature on time? You read the Wiki, which is out of date and in sync with the current code base. You read the code. You don't know how the code works. So you talk to the developer who wrote the code. There are communication issues. I cannot estimate unless I have an understanding of the system.
How do we gain an understanding of the system? Can tests help? Cucumber features does not provide trace-ability. Because, the steps create and call methods on it. We cannot get a big picture view of the system that helps us to estimate. It introduces accidental complexity. Bob Martin's suggestions result in bloated code and over-engineering. We don't want Repository pattern and all that Java crap that becomes a heavy burden.
Let's imagine an ideal world where we are not restricted by any programming paradigm. What does the ideal solution look like? We need a trace-ability matrix that shows which use-cases map to which class and methods. Some of the classes are re-used by more than one-use case so we have some reuse of code. These shared classes are called tangling. The wide spectrum of classes that collaborate to achieve a high-level use case is called scattering. The use-cases are cross-cutting because they cut through different layers of the system.
In a well-designed system we have layered architecture where we separate the view, the controller and the persistence layer. This allows us to allocate work according to the strength of a developer. As long as we obey the contract between the layers, teams can work in parallel.
How much time do you think you spend on maintenance as a developer? Microsoft did a survey and found out that 90% of the developer time is spent on maintenance. If you reduce that by half, you can save 50% of your maintenance cost.
Ideally I want to glance at the code and instantly know which part of the code has the use case that my manager is talking about. Read my blog post on why using interactor gem is a bad idea.
I don't use Rails filters for business logic. It is very difficult to reason about the code. I thought only others write bad code. I consult for start-ups, I see code written by inexperienced developers, find missing abstractions. Make the view dumb, thin controller and fat models. Then I realized the projects that I developed from scratch, after a few months when I saw the code base, I had 'WTF' moments. What was I thinking? When does this thing get called? Is it even used anywhere? Can I delete it? How do I use this feature?
Why Not Use Tests for Traceability
People get very clever in tests. Ideally, I want to see 'Once upon a time, lots of things happen, then they lived happily ever after'. The tests does not tell me a story. Here is the link to my solution that aims to be a trace-ability matrix. Maybe one of you can create a gem that will analyze the code and create a nice matrix. This matrix can be kept in sync with the code because it is generated by analyzing the code. It be part of the build system, where a post-checkin hook can get it gets published to the wiki automatically. You can use this as a starting point to do impact analysis. What is the impact of this new requirement? How many classes and methods will have to change? Based on that you will get an idea of the complexity of the new requirement.
Question from the audience after browsing my code above. Why not put all the uses cases for an actor into the same file?
Because the only thing I liked about the Interactor gem is that when you open the interactor folder you get a list of all use cases, it shows what the system can do. I don't like the fact that the class names are verbs. Ideally, you want the class names to be noun and the method names to be a verb. I have seen interactor gem more often being abused in the projects that I have been involved. I also think naming the classes with the verb as breaking the basic OO design principles. If you are hitting the limits of OO paradigm, then you need to think about other ways of solving the problem.
When a failure happens, you have to fail loudly. That means raising an application level exception. The reason is that it is extremely difficult to hunt down bugs that are hidden behind some code that is failing silently. I have spent weeks to find these kind of bugs. If you see the home page of interactor gem, you will see they are checking for a flag to check for success/failure.
I also don't like the proliferation of so many classes with just one method. Why do we need a class for each step in a use case? It does not make much sense to me.
Possible Solution
Luckily Ruby allows the file name for a class to be anything. So we can have the file name named after the use case name.
I read the Ivor Jacobson's book Use Case Oriented System written in the 1990's. He talks about describing the use cases that is agnostic of the technology. When a developer works with the use cases, the use cases needs to be converted to objects with responsibilities. Even if you have no semantic gap between your code base and the use cases, you still have a mismatch between the user's perspective and the developer's perspective. You might have concepts in the code that does not have any counter part in the use case or the domain.
BDD does not mean using Domain Driven Design. DDD is about using aggregates, entities, architectural patterns and so on. It's not just using the terms used in the domain.
One of the paper I read uses Django framework and uses complicated solution where use cases are store in a repository with use case annotation to achieve trace ability. I don't want to over-engineer and complicate things. Non-invasive tools would be better, where I can run a gem like Rails best practices and get a nicely formatted trace ability matrix.
Can DCI architecture address these problems? What if Ruby 3.0 came up with a new language construct? My solution has an entry point into the system, it does not do any work by itself. It delegates all the work to other objects. It orchestrates the entire use case.
Note for myself: Take a look at concerns and see if you can get rid of the require statements in application.rb.
TDD is Dead Episode 1 Concise Version
David's three major issues with TDD and Unit Testing:
David agrees that you're not done till you have tests. But doesn't like TDD as a way to get there. He thinks people have different brains and thus like different techniques, he doesn't like that TDD gets conflated with the confidence you get from writing the tests first.
Kent agrees that there are cases where TDD is not suitable. In the TDDable code he found he was in an enjoyable flow, but found the other part more tricky. But in the non-TDD part he still used regression tests and short feedback loops. He has no problem mixing both styles. TDD reminds him of how he learned mathematics at school - always needing examples.
David has been in situations where TDD flowed well, but most of his work isn't like that - his question is what are you willing to sacrifice to get that flow? Many people make bad trade-offs, especially with heavy mocking.
Kent said he rarely uses them, he's concerned that those that do mock often find refactoring difficult, while he finds testing makes refactoring easier.
David said his reaction was to seeing people describe TDD in a mock-heavy style as a moral thing to do and the result was a lot of code that was poorly designed due to its desire to enable isolated unit tests.
Next episode will explore how TDD may lead to design damage. This is the concise version of the transcript of the video : Is TDD Dead?
- Confusion over the definition of TDD and unit testing,
- Test-induced damage through using mocks to drive architecture
- How the red/green/refactor cycle of TDD never worked for him.
David agrees that you're not done till you have tests. But doesn't like TDD as a way to get there. He thinks people have different brains and thus like different techniques, he doesn't like that TDD gets conflated with the confidence you get from writing the tests first.
Kent agrees that there are cases where TDD is not suitable. In the TDDable code he found he was in an enjoyable flow, but found the other part more tricky. But in the non-TDD part he still used regression tests and short feedback loops. He has no problem mixing both styles. TDD reminds him of how he learned mathematics at school - always needing examples.
David has been in situations where TDD flowed well, but most of his work isn't like that - his question is what are you willing to sacrifice to get that flow? Many people make bad trade-offs, especially with heavy mocking.
Kent said he rarely uses them, he's concerned that those that do mock often find refactoring difficult, while he finds testing makes refactoring easier.
David said his reaction was to seeing people describe TDD in a mock-heavy style as a moral thing to do and the result was a lot of code that was poorly designed due to its desire to enable isolated unit tests.
Next episode will explore how TDD may lead to design damage. This is the concise version of the transcript of the video : Is TDD Dead?
Wednesday, January 28, 2015
How to download an entire site to your machine
1. brew install wget
2. wget --recursive --no-clobber --page-requisites --html-extension --convert-links --domains somedomain.com http://somedomain.com/index.html
--domains flag indicates don't follow any external links from somedomain.com site.
--recursive flag tells wget to download all the files on that domain
--page-requisites - get all assets (images, CSS etc)
--html-extension : save files with the .html extension
--convert-links : convert links so that they work off-line
--no-clobber : don't overwrite any existing files
Subscribe to:
Posts (Atom)



