CodeHerb home

Personal notes for coursera's SaaS class
Published on: 25 Feb 2012

I am following coursera's saas-class online, and using this post for keeping track of progress/notes/links etc. These notes are very rough, mostly a personal log of progress…

Lecture notes

Engineering Software is Different from Engineering Hardware (02/25)

Legacy code: old SW meet customer's needs, but difficult to evolve due to design elegance

Waterfall vs Agile

  • Requirements analysis and specification
  • Architectural design
  • Implementation
  • Verfication
  • Operations and Maintenance
  • Works well for important software with specs
  • Plan to throw one away - you are going to anyway ;)
  • If a problem has no solution, it may not be a problem, but a fact, not to be solved, but to be coped with over time.(Peres's Law)
  • Individuals and interactions over processes & tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan
  • Embrace change as a fact of life

Assurance

  • Verification - Did you build the thing right
  • Validation - Did you build the right thing
  • Testing - Exhaustive testing infeasible
  • Use Automation, Coverage, Regression testing, Integration testing, Test Driven Design

Productivity

  • Clarity via conciseness
    • Syntax: short and easier to read
    • Raise the level of abstraction
  • Synthesis
    • Automatic code generation
  • Reuse
    • Procedures and functions
    • Standardized Libraries
    • OOP
    • Design Patterns
  • Automation and tools
    • Replace tedious manual tasks with automation to save time, improve accuracy
    • Concerns (Dependability/ UI)
    • IMPORTANT SKILL - LEARN NEW TOOLS ALL THE TIME

Sotware as a service

  • SaaS delivers SW & data as a service
  • No install worries
  • No data loss
  • Easy for groups to interact with same data
  • No compatibility hassles for developers
  • 1 copy - easier upgrades/features

SOA

  • SW architecture where all components are designed to be services
  • Apps composed of interoperable services
  • Steve Yeggi - SOA rant

Cloud computing, fallacies, pitfalls

  • Communication
  • Scalability
  • Dependability
  • Cluster - commodity hardware
  • Utility Computing / Public Cloud Computing
  • AWS - 42nd fastest computer in the world @ $700/hr!

SaaS Architecture

Web as a Client-Server System; TCP/IP Intro

  • Internet: request/reply oriented
  • Client/Server v-s Peer-to-Peer(bittorrent) architecture
  • Localhost - 127.0.0.1
  • IP - no-gaurantee, best-effort service
  • TCP - makes IP reliable by detecting "dropped" packets
  • TCP ports allow multiple TCP apps on same computer
  • DNS - maps names to IP addresses
  • HTTP - ASCII based request/reply protocol
  • Protocol versions & status code; Response Header and Response Body
  • nc -l <portnumber>
  • HTTP is stateless! Cookies to the rescue
  • Per-user state: customization/ click tracking etc.

3-tiered Shared-Nothing Architecture and Scaling

  • map URI to correct function
  • pass arguments etc.
  • invoke program on server/storage etc.
  • Presentation layer/ App Layer/ Database layer
  • Developer environment vs medium-scale deployment vs large-scale deployment
  • Sharding v/s Replicate data

Model-View-Controller Architecture

  • separate organization of data (Model) with presentation(UI) using a controller
  • View 'indirectly' interacts with Model
  • Each entity has a model, controller & set of views
  • Establishing connections between different views?
  • Models often talk to each other!
  • Alternatives
    • Page Controller <Each view has a controller>
    • Front Controller <One Controller>
    • Template View (PHP) <No controller - embeded PHP>

Models, Databases and ActiveRecord

  • How to represent persisted object in storage
  • In-Memory vs In-Storage?
  • CRUD -> serialize / deserealize
  • ActiveRecord : every model knows how to CRUD itself
  • Rails Models store data in RDBMS
  • Each model in its own table, each row is an instance of the model
  • Alternative: DataMapper -> each model defines its own CRUD. Google App Engine. No RDMS -> easier to scale?. Difficult to map relationships without models

Controllers, Routes and RESTfulness

  • Route maps <HTTP request, URI> to controlloer action
  • Rails routing:
    • Map URI -> method
    • Easily create <URI> calls
    • Parse parameters passed to URI
    • CRUD routes
    • REST (Representation State Transfer)
    • Each URI has all the information it needs to render its view

Templates, Views and HAML

  • Views -> markup with interpolation
  • Template View Pattern: HAML + closure
  • Alternate: Transform View pattern
  • You can put code in view, but you shouldn't. HAML makes it intentionally awkward.

Ruby and Rails Basics

Ruby 101

  • Interpreted
  • Object-Oriented
    • Every operation is a method call
  • Dynamically types - objects have types but variables don't
  • Dynamic
    • add, modify code at runtime
    • reflection
  • Naming conventions
    • ClassNames
    • methods & variables use snakecase (?!)
    • CONSTANTS(scoped) & $GLOBALS
    • symbols: immutable string whose value is itsemlf
      • :rails.tos == "rails" "rails".to_sym == :rails :rails == "rails" => false
      • A symbol specifices that it is one of a fixed set of strings, and not a random string
    • There are no declarations
      • local variables myst be assigned before use
      • instance & class variables ==nil until assigned
      • OK x=3; x = 'foo'
      • Array -> no type x = [1, 'two', :three]
      • Hash: w = {'a' => 1, :b=>[2,3]}
    • Methods -> everything passed by reference
    • http://rubular.com for your regex needs
    • regex syntax is simiar to perl

Ruby Objects and Methods

  • Even integers and nil are true objects
  • mystr.length => mystr.send(:length)
  • "implicit conversion" is not in the type system but in the instance methods! Whoever is the receiver of the method decides what to do with it.
  • a.b means -> call method b on object a! ALWAYS
  • << destructively modifies its receivers

OOP in Ruby

  • class SavingsAccount < Account #inheritance
  • constructor: initialize
  • @balance -> instance variable
  • need to define getter/setter def balance, def balance= {special syntax}
  • @@bankname #class (static) variable
  • def self.bankname {self -> class(static) method name}
  • A class is an instance of Class!
  • attraccessor :balance {easier to create a simple getter/setters}
  • no multi-inheritance (mix-in!)
  • everything is a method call!
  • most "operators" actually instance methods
  • destructive methods have ! at the end
  • ? after a method call means it returns a boolean and has NO side effects
  • ! after a method call means it modifies the object it is called on OR the parameters passed in. This seems to be inconsistent at best.

Ruby Metaprogramming

  • acct.deposit(eurotodollars(100))? Nope - lets do it in an awesome way
  • acct.deposit(20.euros)! Open Numeric class and define euros class Numeric; def euros; self * 1.3 ; end
  • methodmissing! -> if you try to do a method that doesn't exist
  • gets "name of the method" and "params"
  • if methodid.tos == 'euro' self.send('euros') else super #default
  • how about more currencies? Use a hash and methodmissing to do some cool stuff ;)
  • You can "reopen" any calss at any time and add stuff to it!

Ruby blocks, iterators, functional idioms

  • If you are iterating with an index, you are probably doing it wrong!
  • myarray.each do |elt| … end
  • each class kind of handles it's own iteration
  • Expression Orientation

Mixins and Duck Typing

  • Duck Typing - similar to java interfaces
  • ruby really doesn't care about types as long as the objects have the appropriate methods
  • Modules - can't instantiate it (like abstract classes somewhat). Used for namespacing/ Mixins etc.
  • include MyModule (simiar to #include in C++)
  • checks A -> mixin modules -> methodmissing -> punts to super class
  • Example enumerable! - assumes you can respond to each and provides a whole bunch of methods like any, collect, find, etc.
  • Read documentation to figure out what methods needs to be implemented for a Mixin to work
  • File.open('file').select {|s| s=~/aeiou/}! Uses IO#each and String#<=>
  • Modules reuse behaviors - Enumerable, Comparable
  • Classes reuse implementation!
  • Prefer composition over inheritance! (Mixin vs inheritance)

Yield

  • Blocks (anonymous lambda)
  • Ruby -> here is some code to apply to every element, go handle your own iteration. Contrast with java world of creating iterators etc.
  • yield! closures! yummy :)
  • Blocks are closures! They carry their environments
  • Duck Typing, Blocks, Iterators, Closures, Annoymous lamdas

Databases & Migrations

  • Database is golden! Rails provides 3 databases dev/production and test environments each have own DB!!!!
  • How to make changes to DB? Rails solution - migration - script describing changes, portable across DB types (mysql, postgres etc!)
  • Can identify each migration, and some migrations can even be rolledback
  • Can version your migrations - holy moly!
  • Theme: don't do it - automate it!
  • rails generate migration – def up; def down (rollback!)
  • rake db:migrate (Apply migration to development)
  • Production (heroku): heroku rake db:migrate
  • Rails maintains a record of which migrations have been applied - running migrations is idempotent :)
  • Augumenting app functionality -> add models, view, controller

ActiveRecord Basics

  • Subclass from ActiveRecord::Base
  • connects to a model
  • Makes CRUD simple simple simple
  • Database table name derived from Models name Movie->movies
  • Database table column names are getters/setters
    • differs from attrreader; a lot of stuff goes on under the hood
  • Creating / save/ save or save! (! throws exception if operation fails)
  • Create = new + save
  • newrecord? -> works with id to determine if record exists etc.
  • Movie.where("rating='PG'"); allows prepared statements as well
  • where can be chained together efficiently
  • Defrencing happens when defreneced - allows efficient chaining :)
  • find* allows finding by attributes; findallbyrating, findbyrating etc.
  • All findby methods are safe, unless you bang them ;)
  • Update: modify attributes and save, or updateattributes
  • Transaction operations - either all are updated or none
  • Destroy - destroy an instance method
  • m.destroy <-> AR object is destroyed, but you can access the read-only copy (can't modify it)

Controllers and Views

  • Create route in config/routes.rb
  • Add the action in the appropriate *controller.rb
  • Ensure there is a corresponding view!
  • Model -> methods to get/manipulate data
  • Controller -> get data from Model, make available to view
  • Instance variables in controller are available in the view
  • By default view is app/views/<class>/<method>.haml

Debugging

  • Print statements doesn't work as well in SaaS ;)
  • LOGGING!

Homework

Assignment 1

Part 1: fun with strings

def palindrome?(str)
  x = str.downcase.gsub(/\W/, "")
  return x.reverse == x
end
require 'pp'
def count_words(str)
   counts = Hash.new(0)
   str.downcase.gsub(/\W/," ").scan(/\b\S+/) {|key| counts[key] = counts[key] + 1 }
  return counts;
end 

Part 2: Rock, Paper, Scissors

require 'pp'
class WrongNumberOfPlayersError < StandardError ;end
class NoSuchStrategyError < StandardError ;end

def rps_game_winner(game)
  raise WrongNumberOfPlayersError unless game.length == 2
  game.each {|player, move| raise NoSuchStrategyError unless move =~ /(p|s|r)/i }
  rules = {:s => :r, :p => :s, :r => :p}
  :player1 = 0; :player2=1; :name=0; :strategy = 1
  case game[:player1][:strategy].downcase.to_sym
  when game[:player2][:strategy].downcase.to_sym
      return game[:player1]
  when rules[game[:player2][:strategy].downcase.to_sym]
    return game[:player1]
  else
    return game[:player2]
  end
end

 pp rps_game_winner([ [ "Armando", "S" ], [ "Dave", "P" ] ])  

ruby

The logic here is to flatten the whole array, and pick four elements at a time and play the game. We keep doing this iteratively till we are only left with two elements and thus know the winners!

require 'enumerator'
def rps_tournament_winner(tournament)
  tournament = tournament.flatten
  while tournament.length > 2 do
    tournament = tournament.each_slice(4).map { |p1,s1,p2,s2| rps_game_winner [[p1,s1],[p2,s2]] }.flatten
  end
  return tournament
end

# participants = [
#                 [[ ["Armando", "P"], ["Dave", "S"] ], [["Richard", "R"], ["Michael", "S"]]],
#                 [[ ["Allen", "S"], ["Omer", "P"] ], [ ["David E.", "R"], ["Richard X.", "P"]]]
#                ]
# pp participants
# pp rps_tournament_winner(participants)
# pp participants


Part 3

def combine_anagrams(words)
  results = Hash.new([]);
  words.each {|word| results[word.downcase.split(//).sort.join] += [word]}
  return results.values;
end

#pp combine_anagrams(['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream']);