piątek, 23 grudnia 2011

Design patterns - Command

Second post about Design Patterns going to be devoted to Command pattern. It's one of these patterns that can be characterized with one sentence: "Move chunk of code to it's object and execute it as needed".
It might be not very informative, but that's all that is to say about Command pattern, really:)
I always considered examples to be more instructive then theoretical description, so lets consider the following example: "Your task is to design and implement a controller for autonomous race car, controller will be using preset knowledge base for different driving skills: for driving on snow and on road". Not getting into details controller might look like that:
class Driving
  def initializing(skill)
    @skill = skill
  end

  # methods implementing action based on returned value from function drive

  def drive
   @skill.use
  end

end
Now that every time we want our controller to use other knowledge base (other driving skills) all we have to do is to initialize class Driving with appropriate skill class, one might look like that:
class OnSnowSkill
  def use
    "using on snow skills"
  end
end

class OnRoadSkill
  def use
    "using on road skills"
  end
end
Now we can use our driving skills like:
Driving.new(OnSnowSkill.new).drive
or when we are driving on solid road:
Driving.new(OnRoadSkill.new).drive
That's the core of command design pattern, separate these that stay constant form these that change. Chunk of code that change should have it own class that encapsulate appropriate actions.

On github You can find full implementation as well as implementation of command design pattern using blocks (btw, migration in rails use command pattern and implement it thru block) and some other patterns too.

wtorek, 20 grudnia 2011

Design patterns - Template Method

With these post i would like to start new series on my blog, series devoted to design patterns and their implementation in Ruby.

So, for start, let's look wikipedia to find out whats design patterns really are:
"In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations..." from wikipedia
One of the most basic and commonly used design patterns (used even, implicitly, in other design patterns) is design called "Template method". Basically speaking "Template method" pattern consist of abstract class witch provide template methods and some algorithms that work on these methods, their implementation is provided by subclass.

Consider example:
Your task is to implement two classes, one for simulating driving a car and one simulating driving a motorcycle. One might notice that at some point of abstraction driving these vehicles is similar, you have to start engine, increase speed, stop engine, etc. The differences are how you are doing it. Take a look at the following code:
class DriveVehicle
 def start_engine
  raise "Trying to use abstract method"
 end

 def stop_engine
  raise "Trying to use abstract method"
 end

 def increase_velocity
  raise "Trying to use abstract method"
 end

 def decrease_velocity
  raise "Trying to use abstract method"
 end

 def drive
  [start_engine, increase_velocity, decrease_velocity, stop_engine].join ' and '
 end
end
Class DriveVehicle implements these abstract tasks (template methods) and provide method "drive" that work on them. Implementation of these method is going to be provided by subclass of DriveVehicle, so result of the "drive" method will solely depend on provided implementation.
For driving a car, class implementing it behavior might looks like that:
class DriveCar < DriveVehicle
 def start_engine
  "starting car engine"
 end

 def stop_engine
  "stoping car engine"
 end

 def increase_velocity
  "increasing car velocity"
 end

 def decrease_velocity
  "decreasing car velocity"
 end
end
and for driving a motorcycle like that:
class DriveMotorcycle < DriveVehicle
 def start_engine
  "starting motorcycle engine"
 end

 def stop_engine
  "stoping motorcycle engine"
 end

 def increase_velocity
  "increasing motorcycle velocity"
 end

 def decrease_velocity
  "decreasing motorcycle velocity"
 end
end
using of these classes is as simple as:
DriveCar.new.drive
DriveMotorcycle.new.drive
That's all, that "Template methods" design pattern! :)
Please checkout my github for source code and some tests for these classes.

PS:
I have said that these are abstract methods/classes but thats not true, ruby doesn't provide mechanism for creating abstract class, raising error is as close as it can get;P

środa, 26 października 2011

Ruby on Rails 3.1.1 i Redis jako SessionStore

Ruby on Rails od wersji 2.0 do realizacji pamięci sesji (ang. session store) używa ciasteczek, poprzez mechanizm CookieStore. Jest to koncepcja, z którą mam pewne kłopoty i której nie rozumiem.
W teorii sesja ma być obiektem zapamiętywanym po stronie serwera, a tutaj jest zapamiętywana po stronie użytkownika w ciasteczkach...Przypomina mi to trochę sytuację używania metody GET protokołu HTTP do zmiany danych na serwerze, oczywiście można ją do tego wykorzystać, ale to nie znaczy, że trzeba, a nawet nie należy! Specyfikacja protokołu definiuje do tego celu inne żądania (ang. requests), jak chociaż by POST.
Ale wracając do mechanizmu CookieStore, posiada on jeszcze jedną wadę, dane zapisane w ciasteczkach nie są szyfrowane! Jest to zwykły plaintext z kodowaniem Base64! Wszyscy mogą odczytać informacje zapisane w sesji.
Oczywiście, można powiedzieć, że zapisywanie wrażliwych informacji w sesji jest praktyką dość ryzykowną, niemniej w pewnych sytuacjach może się okazać zdrowym kompromisem pomiędzy bezpieczeństwem użytkownika, a szybkością działania całej aplikacji.
Na szczęście Ruby on Rails umożliwia bardzo prosty sposób zmiany "session stora", wystarczy edytować plik konfiguracyjny config/initializers/session_store.rb, który standardowo wygląda mniej więcej tak:

config/initializers/session_store.rb:

# Be sure to restart your server when you modify this file.
{ApplicationName}::Application.config.session_store :cookie_store, 

key: '_{ApplicationName}_session'

# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails generate session_migration")
# {ApplicationName}::Application.config.session_store :active_record_store

Jak widać na listingu powyżej, bardzo prosto (jak zawszy w przypadku railsów ;P) można pamięć sesji realizować za pomocą bazy danych. Jest to dość bezpieczny sposób. Aplikację można uruchomić na kilku serwerach, które będą się łączyć z bazą danych i utrzymywać informację o połączeniu z użytkownikiem.
Sposób fajny tyle tylko, że wolny...każdy 'select' ma znaczenie...jak mawiają starzy górale...

Ciekawym kompromisem zdaje się być wykorzystanie jako SessionStore szybkiej bazy danych jak na przykład Redis. Jest to moim zdaniem jeden z ciekawszych projektów wpisujących się w nurt NoSQL databases. Po informacje o tej bazie odsyłam na stronę projektu. Tutaj tylko powiem, że jest to baza typu key-value, która rezyduje w pamięci RAM (stąd jej duża szybkość), dodatkowo od czasu do czasu zrzucająca informacje na dysk.

Pierwszym krokiem w celu wykorzystania bazy Redis jako SessionStore (poza oczywiście zainstalowaniem samej bazy) jest zainstalowanie gemu redis-store. 
W przypadku Ruby on Rails 3 wystarczy dodać gem 'redis-store' do pliku Gemfile i wywołać komendę bundle. 
Kolejnym krokiem jest edycja pliku config/initializers/session_store.rb
config/initializers/session_store.rb:
{ApplicationName}::Application.config.session_store :redis_session_store, :servers => "redis://my_secreat_password@127.0.0.1:6379/2"
gdzie poza wyborem SessionStora jako :redis_session_store przekazujemy hasha z informacjami jak należy łączyć się z bazą, tj: hasło, adres bazy, na jakim porcie nasłuchuje i którą bazę użyć. Można także użyć opcjonalne parametry: :expire_in - czas TTL w sekundach oraz :has_prefix - do ustawienia przestrzeni nazw.

To wszystko! Od teraz wszystkie informacje związane z sesją będą zapisywane w bazie Redis! A nasza aplikacja będzie szybka i bezpieczna:) 

niedziela, 25 września 2011

Faker i bezpieczny email.

Kiedyś używałem taki fajny gem Faker, który służy do generowania fałszywych danych, bardzo przydatna sprawa przy wypełnianiu wszelkiego rodzaju pól, formularzy, czy też przy pisaniu automatycznych testów.
No i tu pojawia się problem, a mianowicie przy pomocy Fakera można wygenerować fałszywego użytkownika, tzn: fałszywe nazwisko, telefon, adres zamieszkania i email...który może się zdarzyć zupełnie przypadkowo prawdziwy.

Sprawa może być tym bardziej przykra jeśli wysyłamy w programie na te adresy jakiś mail (np: podtwierzający rejestrację użytkownika w serwisie), czasami wysłanie emaila może przebiegać automatycznie, wywoływane jako callback w modelu podczas zapisu użytkownika do bazy danych. Jeden nowy programista w zespole lub chwila zamyślenia no i email zapraszający naszego super tajnego projektu poleciał do jakiegoś pana za oceanem...

Właśnie dlatego postanowiłem napisać rozszerzanie do Fakera, które będzie generować tylko i wyłącznie bezpieczne adresy email, z domeny example.{com|org|net}. Jak zawsze szczegóły można zobaczyć na moim koncie GitHuba . Tym razem wyjątkowo skromnie, raptem kilka linijek kodu, licząc z testami ;)

Użycie też bardzo proste:
require 'faker'
p Faker::Internet.safe_email




Faker od wersji 1.0.1 posiada metodę safe_email :D

poniedziałek, 19 września 2011

Sinatra, a zmienne instancyjne w CoffeeScript.

Jakiś czas temu, zagłębiając się w Sinatre stanąłem przed problemem jak uzyskać dostęp do zmiennych instancyjnych z poziomu CoffeeScriptu?. Czytając dokumentację zauważyłem, że szablony są przetwarzane w tym w tym samym kontekście, metody obsługujące połączenie (ang: route handlers) więc od strony "technicznej" nie powinno być problemu, pozostało tylko pytanie jak przetworzyć kod rubiego (a tym samym zmienne) w pliku CoffeeScritp?

Odpowiedz okazałą się zaskakująca, a mianowicie zważywszy na fakt, że wybierająca silnik, tj.: haml, coffee, erb do przetworzenia templetu, oprócz klucza wskazującego plik z katalogu "views", przyjmuje również także zwykły ciąg znaków (ang embedded template)! Więc wystarczy napisać coś w stylu:

server.rb:
require  'sinatra'

get '/script.js' do 
  @msg = " 'Dynamicly created JS! Yea!' "
  coffee( erb(:script) )
end

views/script.erb:
i=10
alert <%= @msg %>

i odpowiedz, jaką dostaniemy po skierowaniu przeglądarki na adres /script.js to:

(function() {
  var i;
  i = 10;
  alert('Dynamicly created JS! Yea!');}).call(this);

Ha! A więc działa! Tyle tylko, że jest to bardzo brzydkie rozwiązanie, bo żądamy pliku js, przetwarzamy plik script.erb, który tak naprawdę jest plikiem CoffeeScript...

Rozwiązaniem było by zmuszenie Sinatry do rozpoznawania plików coffee.erb jako szablonu z wbudowanym kodem rubiego i przetworzeniem go najpierw za pomocą silnika erb, lub dodaniem nowej opcji wymuszającej przewożenie templetu za pomocą silnika erb, tj. żeby było możliwe wywołanie templetu coffee z dodatkową opcją:
coffee :script, :preprocess => :erb
W dalszej części skupmy się na tej drugiej opcji, gdyż wydaje się programistycznie ciekawsza ;)

Słowem wstępu, zaznaczyć należy, że wszystkie templety dostępne w Sinatrze, tj: haml, erb, coffee, itdmają taką samą listę przyjmowanych argumentów (na przykładzie erb ):
erb :template_key, options={}, locals={}
Co nie znaczy, że Hash locals, który powinien być wykorzystany do przekazania zmiennych do templety jest zawsze wykorzystywany/zaimplementowany;) Tak też właśnie jest w przypadku silnika coffee

Przeglądając kod Sinatry zauważyłem, że żeby dodać nową opcję do Hasha optionswystarczy zmodyfikować metodę coffee (okolice linijki 510 w pliku base.rb).
Nowa, zmodyfikowana wersja wygląda następująco:

def coffee(template, options={}, locals={})

  options.merge! :layout => false, :default_content_type => :js
         
  if options.has_key? :preprocess
    @preferred_extension = "coffee." + options[:preprocess].to_s
    data = render options[:preprocess], template, options, locals
    options.merge! :layout => false, :default_content_type => :js
    render :coffee, data, options, locals
  else
    render :coffee, template, options, locals
  end
end


Jeszcze tylko jedno, skoro zmieniliśmy rozszerzenie wyszukiwanego pliku (z .coffee na .coffee.erb) za pomocą zmiennej @preferred_extension musimy zabronić ponownemu ustawieniu jej w metodzie compite_template w okolicach linijki 584 pliku sinatra/base.rb, tj:

@preferred_extension = engine.to_s unless options.has_key? :preprocess


Dzięki tym modyfikacją mogłem przepisać kod z pliku server.rb do postaci:
require  'sinatra'

get '/script.js' do 
  @msg = " 'Dynamicly created JS! Yea!' "
  coffee :script, :preprocess => :erb
end 
Plik, w którym teraz znajduje się CoffeeScript z dodanym kodem rubiego znajduje się w views/script.coffee.erb czyli jest tak jak być powinno:) 

Dla wszystkich zainteresowanych zmodyfikowaną wersją Sinatry, kod dostępny jest na GitHubie.

PS: Jest to mój pierwszy post, więc proszę o odrobinę wyrozumiałości, oraz wszelkie możliwe rady :)