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
Sunday, April 05, 2015
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
Wednesday, January 21, 2015
Top 10 Reasons Why Test Driven Development in Ruby Course is Awesome
Test Driven Development in Ruby Course is a comprehensive online course that covers the basics of Test Driven Development in Ruby for beginners. This course aims to help beginners to overcome difficulty in learning TDD. Each lessons in the course has hands on exercises to reinforce the material. You will learn TDD by applying the concepts in the lessons. At the end of the class, students will have worked through some common interview problems and gained skills that can be used to answer questions in an interview.
- This course is designed by a developer for developers
- It makes complicated concepts easy to understand
- It is hands on step-by-step guide to learning TDD
- It gives a solid foundation for a beginner to TDD
- You will be doing Test Driven Development in Ruby in less than 4 hours
- Access to the entire transcript that is not released to the public yet.
- Access to the transcript in audio form that is not released to the public yet.
- Lifetime access to 42 lectures and 8 quizzes
- 3.5 hours of high quality content
- Use the downloadable checklists to guide you when coding
This course is the result of teaching one-day TDD boot-camps and TDD tutorials for Silicon Valley Ruby Meetups. I have spent more than 500 hours and thousands of dollars to create this course. Click on the image below to enroll for this course now.
Subscribe to:
Posts (Atom)






