from dot net_to_rails

31
From .NET to Rails, A Developers Story

Upload: pythonandchips

Post on 08-May-2015

11.322 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: From dot net_to_rails

From .NET to Rails,A Developers Story

Page 2: From dot net_to_rails

Who the f**k is Colin Gemmell

.NET Dev for 3.5 years

Webforms, MVC, Umbraco

Big on ALT.NET ideals

Moved to Ruby on Rails in May 2010

Started the Glasgow Ruby User Group in March 2011

Page 3: From dot net_to_rails

Why Ruby and Rails

Cheaper than developing with .NET

Arguably faster and more productive

Easier to test your code

Open and free development

Page 4: From dot net_to_rails

Why Ruby and Rails

This man pays me to.

@chrisvmcd

Page 5: From dot net_to_rails

.NET Development Environment

Window XP/Vista/7

Visual Studio 20XX

Resharper or Code Rush

Page 6: From dot net_to_rails

My First RubyDevelopment Environment

Window XP/Vista/7

Rubymine

Cygwin

Ruby Gems

Interactive Ruby Console (irb)

Page 7: From dot net_to_rails

Windows Problems

Rails traditionally deployed on Linux OS

Gem’s often use Linux kernal methods

or Linux Libraries

Engineyard investing on Rails development with windows

Page 8: From dot net_to_rails

Development Environment

VMware workstation

Ubuntu

VIM + a lot of plugins

Ruby Gems

Interactive Ruby Console (irb)

Rubymine

Page 9: From dot net_to_rails

Development EnvironmentFind what is right for you.

Page 10: From dot net_to_rails

Ruby

Ruby Koans (http://rubykoans.com/)

Page 11: From dot net_to_rails

Ruby and SOLID

Single responsibility

Open/Closed

Liskov Substitution

Interface Segregation

Dependency Injection

Page 12: From dot net_to_rails

Ruby and loose coupling

In .NET we use Interface and Dependency

Injection to achieve loose coupling

Ruby is loosely coupled by design.

Everything and anything can be changed.

Thanks to being a dynamic language and……

Page 13: From dot net_to_rails

Ruby and Monkey Patching

Page 14: From dot net_to_rails

Add New Functionality to Ruby"Developer Developer Developer is awesome".second_word

NoMethodError: undefined method `second_word' for "developer developerdeveloper":String

class Stringdef second_work

return self.split(' ')[1]

endend

"Developer Developer Developer is awesome".second_word

=== “Developer”

Extension methods anyone?

Page 15: From dot net_to_rails

Changing implementation

class ZombieKiller

def kill

self.shotgun.fire

end

end

zombie_killer = ZombieKiller.new

puts(zombie_killer.kill)

=== Zombie head explodes

class ZombieKillerdef kill

self.axe.throwend

end

zombie_killer = ZombieKiller.newputs(zombie_killer.kill)=== Zombie Falls off

Page 16: From dot net_to_rails

Are you scared yet?

If the idea of monkey patching scares you a little, it probably should. Can you imagine debugging code where the String class had subtly different behaviours from the String you've learned to use? Monkey patching can be incredibly dangerous in the wrong hands.

Jeff Atwood

http://www.codinghorror.com/blog/2008/07/monkeypatching-for-humans.html

Page 17: From dot net_to_rails

Testing Ruby and Rails

Page 18: From dot net_to_rails

Testing Ruby and Rails

Testing ensures code behaves correctly

Tests ensure code compiles

Debugging support patchy at best

Its all right, testing is a lot simpler

Page 19: From dot net_to_rails

How I Tested .NET

[TestFixture]

public class ZombieKillerTest : SpecificationBase{

private ZombieKiller zombieKiller;

private Zombie zombie;

public override void Given(){

var repo = Mock<IZombieKillerRepository>();

zombie = new Zombie(Strength.Week,Speed.Fast);

zombieKiller = new ZombieKiller(repo);

repo.stub(x => x.UpdateZombie).returns(true);

zombieKiller.weapon = Weapon.Axe;

}

public override void When(){

zombieKiller.kill(zombie);

}

[Test]

public void should_depacite_zombie(){

zombie.status.should_eqaul("decapitated");

}

}

public class ZombieKiller : IZombieKiller {private IZombieKillerRepository _repo;public ZombieKiller(

IZombieKillerRepository repo){_repo = repo;

}

public void Kill(Zombie zombie){zombie.status = "decapitated“;repo.UpdateZombie(zombie);

}}

Page 20: From dot net_to_rails

Example RSpec test

describe "when killing a zombie" do

class Zombie

def save

true

end

end

before do

@zombie = Zombie.new(

:strength => :week, :speed => :fast)

@zombie_killer = ZombieKiller.new(

:weapon => :axe)

@zombie_killer.kill(@zombie)

end

it "should be decapitated if hit with axe"

do

@zombie.status.should eql(:decapitated)

end

end

class ZombieKillerdef kill zombie

zombie.attack_with self.weaponend

End

class Zombie < ActiveRecord::Basedef attack_with weapon

#do some logic to see #what happened to zombie

self.saveend

end

Page 21: From dot net_to_rails

Range of Testing

In .NET there are a lot of test frameworks

Ruby test frameworks include TestUnit, RSpec, Shoulda and Cucumber

Rails encourages testing at all levels.

All extremely well documented.

Page 22: From dot net_to_rails

The Rails Way

One project layout and only one layout

Principle of least surprise

Change it at your own risk

Heavily based on conventions e.g.

ZombieController > ZombieControllerSpecZombie > ZombieSpec (or ZombieTest)

Zombie > ZombieController

This can be applied to .NET too

Page 23: From dot net_to_rails

Makes really fast to get going with project

The number one reason for slow apps (IMHO)

Is to easy to write code that over uses the database

Often don’t/forget to think about DB

The Curse of Active Record

Page 24: From dot net_to_rails

1 class Session < ActiveRecord::Base

2 # name > string

3 # code > string

4

5 validates_uniqueness_of :name, :code

6 include SessionModel

7

8 def generate_code

9 return if !(self.code.nil? ||self.code.empty?)

10 full_code = ""

11 while (true)

12 code = "%04d" % rand(9999)

13 full_code = “ABC#{code}"

14 break ifSession.code_is_unique?(full_code)

15 end

16 self.code = full_code

17 end

18 end

The Curse of Active Record19 module SessionModel20 def self.included klass21 klass.extend ClassMethods22 end2324 module ClassMethods25 def code_is_unique?(code)26 return self.find_by_code(code).nil?27 end28 end29 end

Spot the database calls...

Page 25: From dot net_to_rails

class Session < ActiveRecord::Base

# name > string

# code > string

validates_uniqueness_of :name, :code x 2

include SessionModel

def generate_code

return if !(self.code.nil? ||self.code.empty?)

full_code = ""

while (true)

code = "%04d" % rand(9999)

full_code = “ABC#{code}"

break ifSession.code_is_unique?(full_code)

end

self.code = full_code

end

end

The Curse of Active Recordmodule SessionModel

def self.included klassklass.extend ClassMethods

end

module ClassMethodsdef code_is_unique?(code)

return self.find_by_code(code).nil?end

endend

This was production code. The names have

been changed to protect the innocent

Page 26: From dot net_to_rails

.NET deployment predominantly through FTP or copy to file share

But what about databases, migrations, queues, externals dependencies etc.

Fear common place on deployment day

.NET Deployment

Page 27: From dot net_to_rails

Deployment is a solved problem in Rails

Built on several parts

Database migration come out of the box

Bundler gets dependency

Use of Chef or Capistrano for externals or configuration changes

Platform as a service combine all of these e.g. Heroku, Engineyard, Brightbox

Ruby Deployment

Page 28: From dot net_to_rails

Shock horror its a demo

Deployment

Page 29: From dot net_to_rails

From .NET to Rails,A Developers Story

Any Questions?

E-mail: [email protected]

Blog: pythonandchips.net

Twitter: @colin_gemmell

Page 30: From dot net_to_rails

Rails Scaling

Page 31: From dot net_to_rails

Scaling Rails

http://tinyurl.com/6j4mqqb

John Adams, Twitter operations