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?

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:
  1. Confusion over the definition of TDD and unit testing, 
  2. Test-induced damage through using mocks to drive architecture
  3. How the red/green/refactor cycle of TDD never worked for him. 
Kent said that programmers deserve to feel confident that their code works, TDD is not the only way to reach that.

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.
TDD in Ruby
  1. This course is designed by a developer for developers
  2. It makes complicated concepts easy to understand
  3. It is hands on step-by-step guide to learning TDD
  4. It gives a solid foundation for a beginner to TDD
  5. You will be doing Test Driven Development in Ruby in less than 4 hours
  6. Access to the entire transcript that is not released to the public yet.
  7. Access to the transcript in audio form that is not released to the public yet.
  8. Lifetime access to 42 lectures and 8 quizzes
  9. 3.5 hours of high quality content
  10. 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.


TDD in Ruby

TDD in Ruby

Friday, December 05, 2014

Upgrading from Rails 4.1.4 to Rails 4.1.8

Problem when upgrading from Rails 4.1.4 to Rails 4.1.8

rails -v
Bundler is using a binstub that was created for a different gem.
This is deprecated, in future versions you may need to `bundle binstub rails` to work around a system/bundle conflict.
Rails 4.1.8


Fix:
$rm -rf bin/*
$bundle exec rake rails:update:bin
zepho-mac-pro:lafon zepho$ rails -v
Rails 4.1.8


Monday, November 24, 2014

Deploying a Rails App on Google App Engine

Deploying a Rails Webapp on GAE should be a piece of cake right? Due to lack of good documentation, it is not that easy. I had to dig around to find the versions of the software installed for Ruby Stack One-Click Deploy.

Here is some useful information to access installed software components.
Apache web server:  

Configuration directory: /etc/apache2
Default website directory: /var/www
Command to start Apache web server: sudo service apache2 start
Command to stop Apache web server: sudo service apache2 stop

Passenger:

Help command: passenger --help
Install directory: /usr/local/rvm/gems/ruby-2.1.1/gems/passenger-4.0.48

MySQL:

Command to access MySQL: mysql -u root -p
Command to start MySQL service: sudo service mysql start
Command to stop MySQL service: sudo service mysql stop

RVM, Ruby and Rails:

RVM Help command: rvm
Rails help command: rails -h
RVM install directory: /usr/local/rvm
Ruby install directory: /usr/local/rvm/src/ruby-2.1.1
Rails install directory: /usr/local/rvm/gems/ruby-2.1.1/gems/rails-4.1.4

Git:
Help command: git --help

Saturday, November 22, 2014

bin/rails:6: warning: already initialized constant APP_PATH

I was getting this error in Rails 4.2 beta when I started the rails server. Solution: run : rake rails:update:bin from rails project directory.

git Illegal instruction: 4 mac 10.7.5

Download the git for Mac 10.7.5  and restart your terminal.

Friday, November 14, 2014

Stripe API Capybara Test Failures

I was getting Stripe::InvalidRequestError: You must supply either a card or a customer id error. To fix this, make sure js is true in your integration test like this:

feature 'Guest Checkout' do
  scenario 'Complete purchase of one product', js: true do
    visit products_show_path
    click_link 'Buy Now'
   
    fill_in "Card Number", with: '4242424242424242'  
    page.select '10', from: "card_month"
    page.select '2029', from: 'card_year'
    click_button 'Buy Now'
   
    expect(page).to have_content('Receipt')
  end
end

Thursday, November 13, 2014

Base Ball Player Statistics

Overview:  For this scenario, we have been asked to write an application that will be used to provide information about baseball player statistics.  Approach this problem as if it is an application going to production.  We don't expect it to be perfect (no production code is), but we also don't want you to hack together a throw-away script.  This should be representative of something that you would be comfortable releasing to a production environment.  Also, spend whatever amount of time you think is reasonable.  If you don't get all the requirements completed, that's ok.  Just do the best you can with the time that you have available.  You may use whatever gems, frameworks and tools that you think are appropriate, just provide any special setup instructions when you submit your solution.

Assumptions:  All requests currently are based on data in the hitting file.  Future requests of the system will require data from a pitching file as well.  Consider this in the design.

Requirements: When the application is run, use the provided data and calculate the following results and write them to STDOUT.

1) Most improved batting average( hits / at-bats) from 2009 to 2010.  Only include players with at least 200 at-bats.
2) Slugging percentage for all players on the Oakland A's (teamID = OAK) in 2007. 
3) Who was the AL and NL triple crown winner for 2011 and 2012.  If no one won the crown, output "(No winner)"

Formulas:
Batting average = hits / at-bats
Slugging percentage = ((Hits – doubles – triples – home runs) + (2 * doubles) + (3 * triples) + (4 * home runs)) / at-bats
Triple crown winner – The player that had the highest batting average AND the most home runs AND the most RBI in their league. It's unusual for someone to win this, but there was a winner in 2012. “Officially” the batting title (highest league batting average) is based on a minimum of 502 plate appearances. The provided dataset does not include plate appearances. It also does not include walks so plate appearances cannot be calculated. Instead, use a constraint of a minimum of 400 at-bats to determine those eligible for the league batting title.


Data:  All the necessary data is available in the two csv files attached:

Batting-07-12.csv – Contains all the batting statistics from 2007-2012.  
Column header key:
AB – at-bats
H – hits
2B – doubles
3B – triples
HR – home runs
RBI – runs batted in

Master-small.csv – Contains the demographic data for all baseball players in history through 2012.


Please note: We are looking for you to demonstrate you knowledge related to common software practices to include reusability, portability, and encapsulation – to name a few. Work submitted should be in project form and implemented as you were implementing any production solution.


Tuesday, November 11, 2014

How to share files between Virtual Box Ubuntu with Mac OS host computer

1. Create a folder in your Mac home directory, let's say ubuntu-sf.
2. Install guest additions. Click Devices -> Guest Additions and run the installer.
3. Reboot VM
4. Select the Ubuntu image on VM, go to Settings -> Shared Folders
5. Browse to the folder on your Mac you want to share (ubuntu-sf). Name the shared folder (ubuntu-sf)
6. On Ubuntu terminal, run : sudo adduser your-username vboxsf
7. On Ubuntu terminal run: sudo mount -t vboxsf ubuntu-sf /home/bparanj/ubuntu-sf
   Here ubuntu-sf is the name of the shared folder we created in step 5. /home/bparanj/ubuntu-sf is the folder in the
   Ubuntu.


References

How to share files between Virtual Box Ubuntu and host computer
How to automatically mount a folder and change ownership from root in virtualbox


some of the partitions you created are too small ubuntu 12.04 LTS Precise Pangolin

I was getting this error during installation of Ubuntu on Virtual Box. Solution: Increase the hard disk size from default 8GB to something higher. It worked for 45GB.

Tuesday, November 04, 2014

How to get web_console working in Rails 4.2.beta4 project

1. Add the gem to Gemfile.

group :development do
  gem 'web-console', '2.0.0.beta3'
end

2. bundle

3. You can go to the web console by going to the URL : http://localhost:3000/console

You will also see the web console on the bottom of the browser. You can experiment with the Rails environment loaded.

4. You can add "<%= console %>" to any views and play with the web console.

If you restart the server. You need to reload the page to get a new active console session.

For more details : Web Console Ruby Gem

Problem installing nokogiri on Mac OS 10.7.5

Problem: Make sure that `gem install nokogiri -v '1.6.3.1'` succeeds before bundling.

Solution: bundle config build.nokogiri --use-system-libraries
Then run : bundle

libv8 and therubyracer installation problems on Mac OS 10.7.5

The error message is : Make sure that `gem install libv8 -v '3.16.14.7'` succeeds before bundling.
Solution: gem install libv8 -v '3.16.14.7' -- --with-system-v8

Make sure that `gem install therubyracer -v '0.12.1'` succeeds before bundling.
Solution : Change the Gemfile to specify the libv8 version:

gem 'libv8', '3.11.8.13' 
and run bundle

Sunday, October 19, 2014

Copy to Clipboard in Linux

1. Install xclip : sudo apt-get install xclip
2. Copy test.txt to clipboard : cat test.txt | xclip
3. Acess the text from the clipboard: xclip -o

Reference:

1. Copy Output of a Command to Clipboard