Saas 3.10- Databases And Migrations

From Expertiza_Wiki
Revision as of 07:14, 3 October 2012 by Rbyredd (talk | contribs)
Jump to navigation Jump to search

Saas 3.10 - Databases And Migrations

A Database<ref>http://en.wikipedia.org/wiki/Database</ref> is a coherent collection of data with inherent meaning. Random assortment of data is not a database. Data is organized in order to model relevant aspects of reality, so that it supports processes requiring this data. Data Migration is related to transfer of data between storage types, formats, or computer systems. This is performed programmatically to accomplish an automated migration so that humans are free from doing this repetitive task.

Database

A Database is nothing more than a collection of meaningful information. Databases can be of multiple types, for example Distributed Databases, Relational Databases, Flat File Databases. A database could be as simple as a text file with a list of names or it can even be very complex as a large relational database management system.
Examples:

  1. Banking Systems where accounts are maintained and it is made sure that money does not disappear as a result of system failure.
  2. Airline Reservation Systems where the plane details, the airport details and the customer details are maintained.
  3. Hotel Management Systems where the availability of rooms, the rates and the customer details are maintained.

Database Migration

Every application in reality has a database in the back end to store all the relevant data of the application. We should not test the application on database because it may contain valuable data like customer information in a banking system. So editing that data present in the database is not a good idea. The solution Rails<ref>http://guides.rubyonrails.org/getting_started.html</ref> provides for above problem is Defining three different environments: Development, Production and Testing each of which has a separate database and appropriate database types.

The Development Environment is what we use while developing the application. The production environment refers to the database that is used when the application is published in the real world. The testing environment is meant for testing tools. Testing of the application is done using Testing tools which automates the entire testing procedure. Since there are different databases in each environment, the problem that occurs is changes made in one Database do not reflect in the other.

A programmer is also responsible to tell the other developers what changes have been made in the database. Also one has to keep track of which changes need to be run against production machines during deployment. The solution for the above problem that rails offers is data migration. Databases of different types can also be migrated between the three different environments. For example, we may use SQLlite<ref>http://en.wikipedia.org/wiki/SQLite</ref> in Development environment, but we can still migrate into production environment where heroku<ref>http://en.wikipedia.org/wiki/Heroku</ref> may have been used. The source is portable and the back end understands what operations to do on the database.

In reality Rails migrations are similar to version control of databases. Rails migrations is actually used since databases change requires modifications to both code and data. Hence we cannot use a source code version control system like Subversion<ref>http://betterexplained.com/articles/a-visual-guide-to-version-control/</ref> or Sourcesafe<ref>https://wiki.library.ucsf.edu/display/~128507@ucsf.edu/Source+Safe+vs.+Subversion</ref>.

Creating A Migration

A migration is a sub class of ActiveRecord:: Migration which implements two methods: ‘up’ and ‘down’. The “up” method performs the required changes or transformations while the down methods reverses or roll backs them.

A migration can be created using the following command:

rake generate migration CreateCourse

Migration Created :

class CreateCourse < ActiveRecord::Migration
def up
 create_table :course do |t|
   t.string :name
   t.text :description
   t.timestamps
 end
end
def down
 drop_table :course
end
end

The above migration CreateCourse has just been created, but has not been applied to the Database yet. This migration will add a table called courses with string column called name and the text column called description. A primary key column called id will also be created by default. The time stamp columns created_at and updated_at which ActiveRecord populates automatically will also be added. Reversing this migration is nothing but dropping the table.

Migrations can also be used to fix bad data in the database or generate new fields.

For Example:

class AddGradesToStudents < ActiveRecord::Migration
def up
 change_table :students do |t|
   t.boolean :receive_grade, :default => false
 end
 User.update_all ["receive_grade = ?", true]
end
def down
 remove_column :students, :receive_grade
end
end

The above migration adds receive_grades to the students table. We want the default value to be false for new students. But existing students are considered to have a grade, So we use the student model to set the flag to true for existing students.

ActiveRecord<ref>http://api.rubyonrails.org/classes/ActiveRecord/Base.html</ref> provides methods that perform common data definition tasks in a database. A migration is like a Ruby class so you’re not limited to these functions. For example, after adding a column you can write a code to set the value of that column for existing records (if necessary using your models). The kind of object that is yielded as a result of the migration code is object representing table.

Updating Migrations

If you wish to make changes to the migration and you have already run the migration then you cannot just edit the migration and run it again. Rails will consider it has already run the migration, so it will do nothing on running “rake db:migrate”. The migration has to be rolled back and then make changes to the migration and run it. It is not recommended to edit existing migration and that too if it has been run on production systems. Instead, writing a new migration that performs the changes required is better. Making changes to a newly generated migration that has not been committed to source code is relatively safe.

Migrations are stored as files in the db/migrate directory, for every migration class. The name of the file is of the form YYYYMMDDHHMMSS_create_course.rb, that is nothing but a UTC timestamp identifying the migration followed by an underscore followed by the name of the migration.

Boo

Boo<ref>Boo Home[1]</ref> is an open source object oriented language that is used to create Domain Specific languages. Defining basic data structures like array, hash, variables etc are inherently supported in Boo and it makes their creation easier. Although Boo is a statically typed language, these restrictions can be bent once in a while so that the type of objects can be found and manipulated in run time as well (Duck typing).

Visual Studio

Visual Studio has Domain-specific language tools that are designed to help the designer to build a language focusing on the language grammar and characteristics rather than paying much attention to the internal details of the compiler.<ref>Domain specific development[2]</ref> Visual tools are used that help focus on the business requirements of the OODSL rather than worrying about how it works internally.

Groovy

Groovy <ref>Groovy Home[3]</ref> is a dynamic language for the Java Virtual Machine. Also, the syntax is groovy is similar to that of Java, making designing of new OODSLs easier and similar to programming in Java. An example for developing an OODSL in Groovy.

OODSL vs. non-OODSL

When defining a DSL, choosing whether to go with an OODSL or a non-OODSL depends on several factors like the domain for which it is defined, existing DSLs for that domain etc. Non-OODSLs are domain specific languages that do not necessarily embrace object oriented concepts like abstraction, polymorphism etc. OODSLs can be well suited for some situations whereas in other situations, they might be an overkill. Defining a new OODSL when there is an already widely accepted non-OODSL may not be very useful. For example, HTML is the standard method for displaying web pages and it is non-OODSL. Defining a new non-OODSL that replaces HTML may not prove to be significantly advantageous.

Advantages and Disadvantages

Some of the advantages of OODSLs would be:

  • Since OODSLs, by their name, are object oriented, they give the developer an easier alternative to model their applications based on business goals and using real world paradigms.
  • Because of their object oriented nature, the code is generally simple to understand and therefore code maintenance would be easier in OODSLs than in non-OODSLs.
  • Object oriented concepts like encapsulation and abstraction give the code better security when they are modified in the future.


Though OODSLs in general have several advantages over other languages, one must also consider their disadvantages:

  • Defining an object oriented language in general takes more time than defining a normal language because we have to properly define it to include OO concepts.
  • They may not be well-suited for all domains and environments. Sometimes there may be a simpler non-OODSL way to achieve the task.

A Running Example

Given here is a simple example <ref>Example DSL in groovy[4]</ref> for creating an OODSL. The DSL defined here simply prints the text we have specified in the program. This is defined in Groovy.

The definition of our new OODSL is as follows:

package com.solutionsfit.dsl.memotemplate
import groovy.xml.MarkupBuilder
class MemoDsl {
	String toString
	String fromString
	String messageString
	def sections = []
	/**
	* Make a closure. Main definition of the DSL program
	*/
	def static make(closure) {
		MemoDsl memoDsl = new MemoDsl()
		closure.delegate = memoDsl
		closure()
	}
	/**
	* Store the values in the local variables
	*/
	def to(String toString){
		this.toString = toString
	}
	def from(String fromText){
		this.fromString = bodyString
	}
	def message(String messageString){
		this.messageString = messageString
	}
	/**
	* The getText method gets called by the DSL by delegation
	*/
	def getText(){
		doText(this)
	}
	private static doText(MemoDsl memodsl){
		String template = "Memo\nTo: ${memoDsl.toText}\nFrom: 	${memoDsl.fromText}\n${memoDsl.body}\n"
		def sectionStrings =""
		for (s in memoDsl.sections) {
			sectionStrings += s.title.toUpperCase() + "\n" + s.body + "\n"
		}
		template += sectionStrings
		println template
	}
}

A sample program in our newly developed OODSL would be:

package com.solutionsfit.dsl.memotemplate

class MemolDslTest extends GroovyTestCase {
	void testDslUsage_outputText() {
		MemoDsl.make {
			to "Nirav Assar"
			from "Barack Obama"
			message "How are things? We are doing well. Take care"
			text
		}
	}
}

References

<references/>