Saturday, November 24, 2007

Saturday, October 13, 2007

Useful unix tricks

link touseful unix tricks from Paul Gross
part 1
part 2

Tuesday, October 2, 2007

Sea Fish

This picture named 'Sea Fish' is from Le Ngoc Mai, my 8 year old daughter.

Tuesday, September 11, 2007

Friday, September 7, 2007

Calling Java from JRuby

Current JRuby is lack of detail documentation with regard to Java integration, so in certain cases it take me and my colleague a while to figure out how to do.
String to/from Java byte's array
In our recent application, we need to pass image from Ruby to image processing method written in Java. The Java method accept byte array and has result as byte array also. So we need convert Ruby String to Java byte[] and back.
The require 'java' add two methods to Ruby String class
String#to_java_bytes # instance method return Java byte[] 
String::from_java_bytes # class method return Ruby string from Java byte[]
The below code snippet demonstrate it.
require 'java'
include_class 'net.csetech.sq.image.ImageHelper'

File.open('duongpl.jpg') do |f|
  f.binmode
  @original = f.read
end

@reduced_j = ImageHelper.reduce_to_fix_size(@original.to_java_bytes,15000)
@reduced_r = String.from_java_bytes(@reduced_j)

File.open('duongpl-15k.jpg','w') do |f|
  f.binmode
  f.write(@reduced_r)
end
Ruby Array to Java Array
Other example, that we may need is to convert Ruby Array to Java Array. The require 'java' add method Array::to_java(Symbol), that convert Ruby Array to Java Array, where Symbol represent Java Class of the Array's elements. If it is omitted, the result is Java Object[].
['a','b'].to_array(:String) # return Java String[]
['a','b'].to_array # return java Object[]
More about method to_array is on JRuby Cookbook

Saturday, September 1, 2007

API design

Link to API: Design Matters
Link to How to Design a Good API & Why it Matters

ActiveRecord-JDBC 0.5 can not insert object with pre-assigned Id into Oracle Database

If you encountered problem when try to insert object with pre-assigned Id into Oracle Database in JRuby 1.0.1 with ActiveRecord-JDBC 0.5, here is quick fix
module ::JdbcSpec
  module Oracle
     def insert(sql, name = nil, pk = nil, id_value =nil, sequence_name = nil) #:nodoc:
      if pk.nil? || id_value
        execute sql, name
      else # Assume the sql contains a bind-variable for the id
        id_value = select_one(
        "select #{sequence_name}.nextval id from dual")['id'].to_i 
        log(sql, name) {
          @connection.execute_id_insert(sql,id_value)
        }
      end
      id_value
    end
  end
end
The problem is on compatibility of Oracle JDBC driver and execute_insert method of java class JdbcAdapterInternalService. The fix simply remove the usage of execute_insert method. Verification code is below
require 'rubygems'
gem 'ActiveRecord-JDBC','0.5'
require 'jdbc_adapter'
require 'active_record'

ActiveRecord::Base.establish_connection(
 :adapter  => 'jdbc',
 :driver   => 'oracle.jdbc.driver.OracleDriver', 
 :url      => 'jdbc:oracle:thin:@localhost:1521:DEV',
 :username => "scott",
 :password => "tiger",
)

class Emp < ActiveRecord::Base
  set_table_name 'emp'
  set_primary_key 'empno'
end

emp = Emp.new
emp.id = 9999
emp.save

Sunday, August 19, 2007

Ruby require idiom

Ruby Kernel#require(filename) read and execute the specified file only once regardless how many time we call it as opposite to Kernel#load(filename) which reload the file each time. With application having many files, each depend on others without this behavior of Kernel#require(filename), a single file will be read executed multi time, which may not desired from functional and performance's perspective. The Kernel#require(filename) however has an issue, after loading it puts path of a file required in global array $" and does not know if we refer to the same file using different path. e.g.
#file : lib/foo.rb
puts "loading #{__FILE__}"

#file : lib/bar.rb
require File.dirname(__FILE__) + '/foo'
puts "loading #{__FILE__}"

#file : app/runme.rb

require File.dirname(__FILE__) +'/../lib/foo'
require File.dirname(__FILE__) +'/../lib/bar'
puts $"
Then run
ruby app/runme.rb

loading ./app/../lib/foo.rb
loading ./app/../lib/foo.rb
loading ./app/../lib/bar.rb
["app/../lib/foo.rb", "./app/../lib/foo.rb", "app/../lib/bar.rb"]
There are basically few well known techniques to deal with this problem
1. Using absolute path
2. Modifying $LOAD_PATH
3. Using defined?

USING ABSOLUTE PATH
In this variant we always call Kernel#require with a absolute path, the File::expand_path will be used to remove '..' symbol representing parent directory e.g
#file : lib/bar.rb
require File.expand_path(File.dirname(__FILE__)) + '/foo'
puts "loading #{__FILE__}"

#file : app/runme.rb
require File.expand_path(File.dirname(__FILE__)+'/../lib')+'/foo'
require File.expand_path(File.dirname(__FILE__)+'/../lib')+'/bar'
puts $"
run
ruby app/runme.rb

loading D:/huy/rubyapp/require_1/lib/foo.rb
loading D:/huy/rubyapp/require_1/lib/bar.rb
["D:/huy/rubyapp/require_1/lib/foo.rb", "D:/huy/rubyapp/require_1/lib/bar.rb"]
This method is described in post ruby require idiom

MODIFYING $LOAD_PATH
The second quite popular technique is to modify $LOAD_PATH directly e.g.
#file : lib/bar.rb

libpath=File.expand_path(File.dirname(__FILE__)+'/lib')
$LOAD_PATH.unshift(libpath) unless $LOAD_PATH.first==libpath

require 'foo'
puts "loading #{__FILE__}"

#file : app/runme.rb

libpath=File.expand_path(File.dirname(__FILE__)+'/lib')
$LOAD_PATH.unshift(libpath) unless $LOAD_PATH.first==libpath

require 'foo'
require 'bar'
puts $"
In the previous mentioned techniques, the File#expand_path method is used to get absolute path of either file or directory, the same file or directory is kept only once in a relevant global variable.

USING defined?
This technique is very old and frequently used by C programmers to guard header file to include multiple e.g.
#file foo.h

#ifdef __FOO_H

#define __FOO_H

...

#endif
In Ruby, I have seen this technique being applied using Kernel#defined? e.g.

#file : lib/foo.rb
unless defined?(FooDefined)
   FooDefined=true
   puts "loading #{__FILE__}"
end

#file : lib/bar.rb
unless defined?(BarDefined)
  BarDefined=true
  require File.dirname(__FILE__) + '/foo'
  puts "loading #{__FILE__}"
end

#file : app/runme.rb

require File.dirname(__FILE__)+'/../lib/foo'
require File.dirname(__FILE__)+'/../lib/bar'
puts $"
UPDATE on 26-12-2007
The new Kernel#require in Ruby 1.9 store full path in $" make this article obsolete.

Saturday, July 28, 2007

Turn off color in output of ls command

Output of ls command in color mode sometime causes a problem to my eyes. Turn it off is simple, just put
unalias ls
in .bash_profile or .bashrc (in case of Ubuntu Feisty)

Thursday, July 26, 2007

Fixture path in ActiveRecord Testing

I am using fixture in ActiveRecord Testing. I have many test classes, each using fixtures located in different directories. Individual test work fine, but fails when running together in suite. The problem is fixture_path is class attribute/variable of Test::Unit::TestCase so all subclasses of it share the same value.
require 'rubygems'
require 'active_record'
require 'active_record/fixtures'

class TestFoo < Test::Unit::TestCase
   self.fixture_path='/u01/test/fixtures/foo'
end

TestFoo.fixture_path # "/u01/test/fixtures/foo"

class TestBar < Test::Unit::TestCase
   self.fixture_path='/u01/test/fixtures/bar'
end

TestBar.new().fixture_path # "/u01/test/fixtures/bar"
TestFoo.new().fixture_path # "/u01/test/fixtures/bar"
Because the Test Unit framework, load all test classes, then run them, so TestFoo.new().fixture_path get value of TestBar.new().fixture_path. The solution is simple, just define a method fixture_path in each test class (in upcoming version after ActiveRecord 1.15.3, the problem is fixed by change fixture_path to class instance variable see ticket 6672).
class TestFoo < Test::Unit::TestCase
   def fixture_path
      '/u01/test/fixtures/foo'
   end
end

class TestBar < Test::Unit::TestCase
   def fixture_path
      '/u01/test/fixtures/bar'
   end
end

TestBar.new().fixture_path # "/u01/test/fixtures/bar"
TestFoo.new().fixture_path # "/u01/test/fixtures/foo"

Wednesday, July 18, 2007

Exception handling

I have seen a lot of code, that handle exception in the following way
begin
  do_some_things()
rescue
  #... print message, closing file/socket etc. 
end
There is a problem with this style. If there is error, we lost information where it happens because it is quite common that do_some_things() again call methods of others classes located in different files and so all.
I think that it should be a rule, that we alway print/save to logfile backtrace of exception in every exception handling code
begin
  do_some_things()
rescue => e
  require 'pp'
  pp e
  pp e.backtrace
  #... print message, closing file/socket etc. 
end
The backtrace information will help us to identify bug during development and to analyze root cause of exception during operation.

String concatenation

One of common thing that any programs do is concatenate two or more String value, e.g.
first_name = 'huy'
sir_name = 'le'
name = first_name + ' ' + sir_name # huy le
But the above code suffers a problem, if one of concatenated variables is nil, then it will not work. Checking nil is tedious and error prone, a simple solution of this problem is putting concatenated variables into an array, removing nil using compact and using join method to perform concatenation.
first_name= 'huy'
middle_name=nil
sir_name = 'le'
name = [first_name, middle_name, sir_name].compact.join(' ') # huy le

Sunday, July 1, 2007

Ruby block and command/query separation

The recent post Ruby block style do end versus {} on where to use do ... end versus {...} to enclose Ruby block reminds me command/query separation OOP principle.

Friday, June 29, 2007

Easy verification of API behavior via irb

Learning programming language is not just learning language syntax, programmers including myself spend lot of time learning various API. Irb is wonderful tool for learning Ruby API, when I do program in Ruby, I always have Irb open, and I try to run a method of API including core lib, that I am not sure how it works. Comparing to Java, it is much faster and have better productivity.

Open classes

When I want to change or add new behavior to existing class, static typed language give me only two options create new class that either extend existing class or delegate to existing class (in Java world some peoples do aspect oriented programming AOP, but it is little bit complicated and is external to the language).
Ruby give me an ability to modify existing class directly. A cross concern or aspect then can be added easily by modifying existing class.

ADDING NEW FEATURE TO EXISTING CLASS
class Object
   def blank?
      return true if nil?
      return true if respond_to?(:empty?) && empty?
      return false
   end
end
nil.blank? #=> true
''.blank?  #=>true
[].blank?  #=>true
{}.blank?  #=>true
'hello'.blank? #false
[:a].blank? #false
{:a=>1}.blank? #false
The above code define method blank? in class Object, which is root of all Ruby classes. This will result in well behaving instances of NilClass, String, Array, Hash.

DECORATION A METHOD OF EXISTING CLASS
To decorate a method of existing class is just easy as adding new one e.g.
require 'active_support'
class Hash
    alias original_symbolize_keys! symbolize_keys!

    def symbolize_keys!
        each_value do |value|
             value.symbolize_keys! if value.is_a?(Hash)
        end
        original_symbolize_keys!
    end
end
Rails ActiveSupport add method symbolize_keys!, above code decorate it to convert keys to symbol for a hash value if it is also hash.
When modifying an existing class, we shall make sure that the class is already loaded, otherwise we may get a strange behavior. This is specially important in rails, when classes are loaded dynamically using const_missing method. About how to handle this problem, there is good tip reopen with class/module eval on practical ruby blog. Other way to decorate method without using alias is available on replacing methods.

Wednesday, June 27, 2007

Using of keyword based parameter

I plan to have presentation of Ruby Language in enterprise application development for developers of the company I worked for and I am thinking about which message should I pass to them. Instead of trying to give many reasons that others already talked about huge benefit of using Ruby, I decide to give my own very personal reasons why I love Ruby based on my one and half year working with this language.
In early day, when I programed in PL/SQL, I know that PL/SQL support keyword based parameter in procedure/function but I never used this feature, simply I have not recognized the benefit of using it that time.
Ruby does not support keyword based parameter but Ruby programmers fake it easily using hash in combination with symbol. Using this style is very popular in Ruby core lib and Rails. The following example illustrates it, suppose we want to create method create_user that create database user, in traditional position based parameter, we will do like that
def create_user(username,password,ignore_error,force,verbose)
   #.. implementation detail is ignored
end
#calling it
create_user('scott','tiger',false,true,true)
on keyword based version, the method has simply one parameter params
def create_user(params)
   username = params[:username]
   password = params[:password]
   ignore_error = params[:ignore_error]
   verbose = params[:verbose]
   force= params[:force]
   #.. implementation detail is ignore
end
#calling it
create_user(:username=>'scott',:password=>'tiger',:ignore_error=>false,
  :verbose=>true, :force=>true)
The keyword based version is obviously more verbose, requires more typing, but offers several benefits.

MORE EXPRESSIVE AND LESS ERROR
The keyword based version is more expressive, just by looking at how the method is called, we know what is the intention, there is no need to look at the implementation file to figure out what it does. The position based version suffers what Joshua Bloch mentioned in his How to Design a Good API and Why it Matters "Long lists of identically typed params harmful"

GOOD DEFAULT
In the position based version, we can only assign default value for those parameters that are at the end of parameter list.
def create_user(username,password=username,ignore_error=false,force=false,verbose=false)
   #.. implementation detail is ignored
end
#calling it
create_user('scott')
This will not give a flexibility of using default value just for few last one. In the keyword based version, we can archive it easily as follow
def create_user(params)
   username = params[:username]
   password = params[:password] || username
   ignore_error = params[:ignore_error] 
   verbose = params[:verbose]
   force= params[:force]
   
   #implementation detail is ignored
   
   #note that Ruby consider nil as false in condition expression, so we should design 
   #boolean value keyword in such way that its default value is false
end

#calling it
create_user(:username=>'scott',:verbose=>true)
create_user(:username=>'scott',:force=>true)
create_user(:username=>'scott',:ignore_error=>true)
I also see people using Hash::merge to shorten assignment of default values and adding some assertion of accepted keywords e.g
#borrow from ActiveSupport
class Hash
  def assert_valid_keys(*valid_keys)
    unknown_keys = keys - [valid_keys].flatten
    raise(ArgumentError,
    "Unknown key(s): #{unknown_keys.join(", ")}\nValid key(s): #{valid_keys.join(',')}")   
      unless unknown_keys.empty?
  end    
end

class DatabaseSchemaBuilder
  
  attr_accessor :ignore_error,:verbose,:force

  def default_options
    {:ignore_error=>@ignore_error,:verbose=>@verbose,:force=>@force}
  end

  def create_user(params)
    params.assert_valid_keys(:ignore_error,:verbose,:force)
    params = default_options.merge(params)
   
    username = params[:username]
    password = params[:password] 
    ignore_error = params[:ignore_error]
    verbose = params[:verbose]
    force= params[:force]

   #implementation detail is ignored
  end
end
EASY TO CHANGE
When we need lets say adding new parameter to the method. In position based version, we end up with changing contract of the method, which may result in looking at every line of code that use this method and make change unless you put at the end of parameter list with default value.
In keyword based version, it is obvious less painful, just adding one more keyword, setting a default value, anyway change only the method itself, e.g. we want to add parameter :noop, meaning no operation, just for testing.
def default_options
   {:ignore_error=>false,:verbose=>false,:force=>false,:noop=>false}
end

def create_user(params)
   params.assert_valid_keys(:ignore_error,:verbose,:force,:noop)
   params = default_options.merge(params)
   
   username = params[:username]
   password = params[:password] || username
   ignore_error = params[:ignore_error]
   verbose = params[:verbose]
   force= params[:force]
   noop=params[:noop]

   #implementation detail is ignored
end
HIDING DESIGN DECISION
Using position based parameter with little bit long parameter list, I have to decide if put one parameter before other or not. I do not have this problem when using keyword based parameter, so it help me do program faster.

Tuesday, June 19, 2007

Ant depend task

I am writing ruby helper class that will be used in Rakefile to build complex java application. Everything seem to be quite simple, I just copied what has been done by Matt Foemmel in his JRake. The ruby helper class has a method that check if java class is upto date by comparing access time of the class file and the java source file. I believe that Ant javac task does the same.
Using the ruby helper file, my java application most of time get build correctly but sometime, few class files are not upto date. It take me a while to figure out what is going wrong.
The problem is when a java class depends on other, if other class changes then the java file shall be recompiled even though it is not modified. Looking at Ant documentation, I found that Ant solve this problem using depend task.
In order to solve this problem in ruby, I have to do the same as Ant depend task does, read our class file, extract all class references verify if these class references are changed.

Format of Date/Time when using ActiveRecord with Oracle Database

I found no place in ActiveRecord Documentation, that describes how to enter Date/Time into Oracle Database. By looking at source code of OracleAdapter in ActiveRecord, I recognized that ActiveRecord uses Oracle alter session command to specify date format
ActiveRecord::Base.connection.execute "alter session set NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'"
As implication we shall use this format (e.g '2007-06-30' and '2007-06-30 23:01:45' String are accepted) when entering data (e.g in fixture file) to Date Field.

Monday, June 18, 2007

My resume - SUMMARY OF SKILLS


Business Analysis & Leadership

  • Able to attract, retain and lead people. Led team up to 25 developers, responsible for task planning, technical direction, risk management, code inspections, quality control, performance reviews, staff development. Understood how to create working environment to keep people happy, motivated, creative and productive.
  • Solid presentation skill, proven in communication with customers, understanding problems, capturing domain knowledge and turning it into high level requirements in suitable form for development team and other stakeholders.

Domain Knowledge

  • Financial industry: retail and investment banking, automated trading systems, communication protocols including SWIFT, ISO8583 and FIX. Involved in proposal preparation, conceptual definition and prototyping automated trading system for brokerages based on Marketcetera platform.
  • Communication industry: Business processes, practices and standards in communication industry including eTom, SID, OSSJ, Mobile Network Architecture, IN, and TAP3. Hands-on experience in ERP implementation including Billing, Fulfillment, and Accounting.
  • Government sector: Hand-on experience in government sector including law enforcement, criminal justice, immigration. Good knowledge in biometrics technology (face and fingerprint) and it's application in government's projects including national ID Cards, and Immigration.

Software Development

  • More than 15 years experience in developing software products with deep knowledge of architecture / design of multi-tiered client-server systems based on middleware including Tuxedo, J2EE (WebSphere, WebLogic) and other emerging Web framework as Ruby on Rails.
  • Skillful in many programming languages including C/C++, JAVA, SQL, PL/SQL, RUBY. Passionate for the simple and easy to understand software with rich domain model. Well versed in OOP, design patterns (Design Patterns - GoF, Pattern for Enterprise Application Architecture - PEAA, Domain Driven Design).
  • Strong knowledge of algorithms and data structures and their applications in writing a high performance, time critical system for complex business domain.
  • Extensive experience with state of art software development practices such as pair programming, Test Driven Development (TDD), refactoring, continuous integration.

System Integration Using Messaging System

  • More then 7 years in design and implementation of software systems that communicate with each other using asynchronous messages. Understand message creation and processing patterns (Enterprise Integration Patterns) and their applications in real world systems.
  • Engaged as system architect in many projects that use Event-driven Architecture (EDA) and Service Oriented Architecture (SOA) integration style.

Infrastructure's Design, Implementation & Administration

  • More than 10 years experience in design, implementation and ongoing maintenance of complex IT infrastructure, that includes J2EE middleware (WebSphere AS, WebLogic), messaging system (MQ), database (Oracle), Unix servers, clustering system, IBM SAN DS series, IBM Tape libraries TS series, Tivoli Storage Manager, CISCO router, PIX firewall and VMWARE virtual technology.
  • Proven in writing script (SHELL, RUBY, PYTHON) to automate repetitive administrative activities including monitoring, deployment, configuration change, etc.

Wednesday, June 13, 2007

My resume - EMPLOYMENT HISTORY


ING Direct Spain, Jul. 2009 - Present

Infrastructure's Software Engineer

  • Administer softwware infrastructure of WebSphere Application Server, JBOSS AS for direct banking system

ING Direct Japan, Sep. 2008 - Apr. 2009

Technical Analyst WebSphere

  • Maintain middleware infrastructure of WebSphere Application Server and WebSphere MQ for core banking system
  • Plan, install, configure and troubleshoot large scale WebSphere Application Server ND and MQ in AIX environment
  • Perform application software deployment, update, performance tuning and other house keeping activities
  • Provide assistant for application development team in problem identification and solving
  • Middleware Monitoring System: directly involved in design, develop and implement monitoring system for middleware infrastructure including exception, performance, capacity monitoring
  • Application Software Deployment Automation: directly involved in design and implementation system for automatic application software update that ensure fast, reliable, error free deployment with no downtime

Centre of Software Engineering - Vietnam, Dec. 1998 - Jul. 2008

Technical Director

  • Managed software development process and quality
  • Prepared technical proposal and system architecture
  • Provided training/mentoring on software design, pattern, refactoring, testing
  • Participated in various development/implementation projects by rotating between different roles according to the need at each project phase (team leader, project manager, business analyst, software developer)
  • Border Control System: managed the project to design, develop a J2EE application for immigration department and deploy under BEA WebLogic in major international airports across the country, integrate it with existing backend system using messaging middleware and perform data migration. Responsible for all technical aspects including overall architecture, software development, performance, quality control, server installation and production support.
  • Data cleansing for law enforcement agency: led a team to perform cleansing of a massive database of hundreds of million of records. Directly involved in design and development algorithm, data structure and rule engine in C/C++.
  • Utilities Billing - Hanoi Water Work Company: Led a team that implemented a distributed billing and customer management system based on ORACLE and JAVA. In charge of overall system design (including custom developed system, IT infrastructure component selection, data migration strategy) and development of data synchronization module using JMS.
  • Telecom Billing and Order Fulfillment System: Responsible for implementation of high performance (up to 20,000 event per second), nearly real time event rating engine using C/C++, Tuxedo and database in memory technology.
  • Personnel Management Information System - Ministry of Home Affair: Managed the development and implementation the Personnel Management Information System for public sector fund by Swedish Agency for Development Cooperation. The system was developed mainly using ORACLE PL/SQL and ORACLE Database.
  • Electronic Library - Institute of Mathematics - Vietnam: Participated in concept definition, architecture and technology selection (ORACLE and PERL).

Centre of Software Engineering - Vietnam, Jul. 1997 - Nov. 1998

Software Developer, Database Administrator, Team Leader

  • Performed installation, maintenance, support ORACLE Database System
  • Designed, developed and implemented framework/library for data synchronization
  • Utilities Billing - Hochiminh Cities Water Supply Company: managed a final phase of the project to implement of billing and customer's care for Hochiminh Cities Water Supply Company using ORACLE PL/SQL and ORACLE Database. Directly involved in development of module for data synchronization between branches and head quarter
  • Document management system: Installed, maintained, provided support ORACLE Database System ,Ministry of Science and Technology .

Notia Information System - Czech Republic, Apr. 1994 - May 1997

Software developer, Team leader

  • Performed installation, maintenance, support ORACLE Database System
  • Participated in various software development projects under different roles team leader, software developer, database administrator, technical support personnel
  • Custom developed ERP - Altron Czech Republic: Led development team in the project to develop and implement of ERP for a distribution and retail company in Czech Republic using ORACLE database design and GUI development in Borland Delphi.
  • Fixed Asset Management - Eurotel Prague: Participated in design a fixed asset management software for a mobile phone company based in Prague.
  • ERP Package Software: Responsible for development and support of C++ part A/R, A/P of ERP package software, that have been deployed to hundreds of customer in Czech Republic.

Metasoft - Czech Republic, Jun. 1993 - Jan. 1994

Software Developer

  • Developed, customized software, provided technical support
  • Implemented software supporting activities of an accommodation agency

irb and TAB autocompletion

To enable autocompletion on irb, run
irb
require 'irb/completion'
Note to hit double TAB on your keyboard not single one. One of most comprehensive description can be found here

Tuesday, June 12, 2007

My resume - TRAINING AND CERTIFICATION


Oracle E*Business Suite Training (one week at IBM Singapore) - 2005

BEA Tuxedo 8 Administration Training (one week at BEA in Malaysia) - 2002

Project Management Training (3 weeks at Asia Institute of Technology (AIT) Thailand) - 2000

Software Engineering Conference (CASE University of Technology &Thomson CSF) - 1999

AIX 4.3 System Administration Certification (IBM Certified) - 1999

Oracle Certified Professional on Oracle8 DBA - 1999

RS/6000 Solution Sales Certification (IBM Certified) - 1999

Switch Off Convert line breaks

I have problem when try to post some html stuff on my blog. The posted html contains simple table. However Blogger incorrectly displays it, alignment doesn't work, a lot of strange space. I finally recognized that, this is due to enabling "Convert line breaks" feature of Blogger, that encloses line break into html break tag, I switch it off, and everything work well.

My resume - PROGRAMMING LANGUAGE AND TOOLS


Operating Systems

  • AIX 4.3/5L, HACMP 4.3, Solaris 7/8, SCO Unix, Windows NT/2000/XP, Linux (Redhat Debian, Ubuntu)

Middleware

  • Websphere ND 6, WebLogic Server 8.1, Websphere MQ 6, Tuxedo 8.0, Tomcat, Ruby on Rails

Database

  • Oracle8i/9i/10g, Oracle Real Application Cluster, MySQL, Microsoft SQL Server 6.5, Microsoft Access

Programming Languages

  • JAVA, C/C++, Ruby, Oracle PL/SQL, Visual Basic, PASCAL, PROLOG

Tools

  • IDEA IntelliJ, Microsoft Visual C++, Rational Rose, Oracle Designer/Developer, Borland Delphi, Toplink, iBATIS, Subversion,Git, Svn, Ant, Maven, Cruisecontrol , JIRA, Mingle, Microsoft Project & Office Suite

Sunday, June 10, 2007

The secret behind Rails Integration Test

Find what is behind Rails Integration Test on good blog's post named HeadlessApp
$ script/console
Loading development environment.

>> app.class
=> ActionController::Integration::Session

>> app.get "/home"
=> 302

>> app.controller.params
=> {"action"=>"home", "controller"=>"accounts"}

>> app.response.redirect_url
=> "http://www.example.com/login"

Saturday, June 9, 2007

gem's environment

When playing with gem on my Ubuntu machine, I found an useful command
huy@huy-desktop:~/.gem$ gem environment 
Rubygems Environment:
  - VERSION: 0.9.0 (0.9.0)
  - INSTALLATION DIRECTORY: /var/lib/gems/1.8
  - GEM PATH:
     - /var/lib/gems/1.8
  - REMOTE SOURCES:
     - http://gems.rubyforge.org
that shows default gem's environment. By setting the GEM_PATH environment variable to one desire directory, we can share single gem repository across many ruby installations (e.g C ruby and JRuby). The full descriptive information of all gem environments variables can be found in Gem Command References

Thursday, June 7, 2007

Naming Exception Corba Comm Failure

Java RMI, Corba, J2EE are sometime still nightmare for developers including these with more than 2 years working experiences with these technologies like myself. I have encountered a "Naming ExceptionCorba Comm Failure" when remote client try to create InitialContext to my Weblogic server. I did check all small details, everything seem to be OK. My Weblogic server is configured to listen on single host interface named "app-svr" that represents a valid IP address 192.168.2.79. My remote client is configured connect to exact same address 192.168.2.79. However it does not work. At some moment, I changed address that Weblogic server is listening from "app-svr" directly to IP address 192.168.2.79, and suddenly it starts work. It also works when I change back listening IP address of Weblogic server to "app-svr" and at the same time put "app-svr 192.168.2.79" in to hosts file of my remote client. Such behavior of the JVM RMI implementation can cause big trouble most JAVA developers including myself.

Friday, June 1, 2007

Cruisecontrol.rb is too slow

I encountered a problem with Cruisecontrol.rb, the method link_to_code(log) is too slow to process a certain output log, sometime it takes 10 seconds making Cruisecontrol not workable. So for the time being, as workaround, I just comment out this code .
#file: app/helpers/builds_helper.rb
  def link_to_code(log)
    log
=begin    
    @work_path ||= File.expand_path(@project.path + '/work')

    log.gsub(/((\#\{RAILS_ROOT\}\/)?([\w\.-]*\/[ \w\/\.-]+)\:(\d+))/) do
      path, line = File.expand_path($3, @work_path), $4
      
      if path.index(@work_path) == 0
        path = path[@work_path.size..-1]
        link_to ".#{path}:#{line}", "/projects/code/#{@project.name}#{path}?line=#{line}##{line}"
      else
        $1
      end
    end
=end
  end

Friday, May 25, 2007

ActiveRecord testing ouside of Rails

There is many tips about how to use ActiveRecord outside of Rails but rarely about ActiveRecord testing ouside of Rails. I am working on project that use ActiveRecord ouside of Rails and need to create fixture for testing. It take me a little bit of time to figure out how to do. The source code below demonstrates the trick

require 'test/unit'
require "active_record"
require "active_record/fixtures"

ActiveRecord::Base.establish_connection(
 :adapter => "mysql",
 :host => "localhost",
 :username => "nightlybatch",
 :password => "secret",
 :database => "web_orders"
)

#this is because fixture verify existence of rails database configuration
ActiveRecord::Base.configurations[:test] = ActiveRecord::Base.connection
  
class Product < ActiveRecord::Base
end

class TestFoo < Test::Unit::TestCase
 #set fixture path explicitly
 self.fixture_path="c:/temp"
 
 fixtures :products

 def test_ruby_on_rails_should_exist
  assert products(:ruby_on_rails)
 end

end

In order to pass the test, the fixture file products.yml shall be created in directory c:/temp, and products table shall be created in MySQL database
#c:/temp/products.yml
ruby_on_rails:
   id:   1
   name: ruby on rails
rails_recipes:
   id:   2
   name: rails recipes

Thursday, May 24, 2007

Ruby adoption in Vietnam

From the time, I know ruby, it is my favorite language, but it seems that no so many developer in Vietnam is using it. Today I have found Vietnam Ruby site. It is good news, that ruby got an attention in Vietnam and I am not alone, who see the huge benefit of wonderful and humane programming language.

Saturday, May 19, 2007

Notia

At my early time in Notia (in 1993 if my memory is correct), I has participated in a project, that develop a ERP package that includes General Ledges, Account Payable, Account Receivable, Warehouse Inventory modules. The technology used that time was Novell B*trieve as database engine, C++ and for business logic, Borland Turbo Vision for C++ for GUI. At that time, Tran Duc Trung was leader, based on university compiler's knowledge, he developed a kind of Domain Specific Language, that allow end-users or implementors define posting rules using that DSL. The "posting rules" DSL is comprehensive featuring expression, AND, OR boolean condition, with Account, Money concept. Other team member, Martin Smid went so far and defined other DSL for reporting function. we called it FRT. Until now, I have not seen better reporting tool with such flexibility, elegance, and easy to used. Other other side, we also faced a lot problems. One of them is that MS*DOS can not run program with more than 1MB static data segment. C++ is also not good choice for GUI development, we encountered a lot of errors related to allocation/free memory, using pointer. And one of most ironical is in using of the DSL itself. The software developers didn't understand well accounting to be honest we was not willing to learn it on the other hand implementors and customers was not matured enough in using the DSL in effective manner. Despite these facts, Notia was able to sold the software and implement it in hundreds customers including few big names as ABB.

Thursday, May 10, 2007

ruby module_function

Ruby 'module' allows us to define methods then turn these methods into instance methods of a class by using key word 'include'. In ruby world, peoples call this feature 'mixin'. e.g.

module Foo
   def hello
      puts 'hello'
   end
end
class Bar
include Foo
end
Bar.new.hello #=> hello

Sometime we need to call method defined in a module without including the module into a class. We can do it by

module Foo
  def self.world
     puts 'world'
  end
end
Foo.world #=> world

There is a question how do we turn method 'hello' so it can be used in both mixin style and standalone . The answer is using kernel method 'module_function'

module Foo
   module_function :hello
end
Foo.hello + ' ' + Foo.world # => hello world

Sunday, April 29, 2007

Install Ubuntu 7.04

I took time during holiday to install Ubuntu 7.04 (code name Feisty) on my home computer. I thought for people with Unix background like myself, it should be simple exercise. It is not. My home computer is old Pentium IV 2.26 MHz, 768 MB RAM with installed Windows XP SP2 and I decided to install Ubuntu as guest OS on virtual machine using Vmware Workstation. First I used Vmware Workstation to create a machine with 6 GB Hard disk. Since Ubuntu is not on list of Vmware available guest OS, I just selected other Linux as guest OS for my virtual machine. I booted the virtual machine with fresh downloaded Ubuntu 7.04 and followed the instruction on the screen. The first installation got stuck at 69 %, I waited 10 minutes then reboot and try second attempt, that went well until completion. Now I can login using the account/password asked and created by installation program. My first impression is not bad, the screen looks nice on 1024x768 resolution, even sound card works. Pre-installed Firefox 2.0 work smoothly even on virtual machine, Ubuntu accepts an IP address assigned from my ADSL Internet modem automatically thus I got connection to Internet.
1. issue sudo: I want to install some additional software as root however what is password of my well known root?. After few minutes investigation, I recognized that Ubuntu using sudo as mechanism to allow normal account access to root and by default root is locked and no one can neither login as root nor su. To run program using root account, we have type e.g.
 
sudo shutdown -r +15 "quick reboot"
sudo will ask us to enter our password and then run shutdown using root account. I known that sudo mechanism is used also in Mac OSx 10.4 Tiger and it offers certain benefits against traditional root, however I can not change my habit so I unlock root account by enter
sudo passwd 
2. issue apt-get: I want to try ruby so I type in command line terminal
ruby
Ubuntu is intelligent enough to answer that ruby is not installed and offer me that I can install ruby by using
sudo apt-get install ruby
I tried and it works. The apt-get is Ubuntu package manager (now I know that it is from Debian and Ubuntu is rooted from Debian). It does all things: downloads required software including dependencies, installs and configures. If we does not know name of software package, then Synaptic Package Manager is application that offers features such as listing, installing and uninstalling software package. apt-get use configuration on /etc/apt/sources.list, which contains list of ftp servers storing debian distribution package.
After adding new repository into /etc/apt/sources.list, hit 'reload' button to get package information from the new added repository.
3. issue add path: I download and install SUN JDK 1.5.0_11 and want to add JDK 1.5 to PATH so I can type java, javac, etc. I created .bash_profile in home directory and add two following line
export JDK_HOME=~/jdk1.5.0_11
export PATH=~/jdk1.5.0_11/bin:$PATH
and do logout/login, it doesn't work. I tried to put these line to .xssesion, after that I can't login to the system anymore and have to login using failsafe session to remove this .xsession file. Looking at documentation and even googling doesn't help. At the end I realized that I should add these line at the end of .bashrc. Then it works in both cases either I login using X-Desktop or terminal using Windows putty.
4. issue Vmware tools: we can not install Vmware tools using Vmware provided package, the Feisty kernel version simply does not match. However Ubuntu provides its own vmware tool package. Installation is pretty simple, just type
uname -a
to get kernel version, my kernel version is 2.6.20-15 and then invoke apt-get
 
sudo apt-get install vmware-tools-kernel-modules-2.6.20-15
Finally reboot to take effect. To be honest, I have not observed better response from any application as Vmware claimed.
5. issue update time: To keep your clock synchronized, install ntpdate package as follows
sudo apt-get install ntpdate
sudo /etc/network/if-up.d/ntpdate
sudo crontab -e 
@hourly /etc/network/if-up.d/ntpdate
6. issue missing c-header files: Ubuntu striped down in order to keep installation CD small and installation process fast. The result is default installation does not contain packages that developers normally expect. I got into trouble when I tried to compile a c program, gcc told me that file dlfcn.h is missing. I guested that some lib is missing but can not figure out which package contains the file. After spending time on Google, I found Ubuntu Package Web Site, where I can enter file name and search for package containing that file.

Monday, April 16, 2007

Create boot image in AIX

To create boot image e.g. on hdisk2 just type
# bosboot -a -d hdisk2 --> update the boot image information
# bootlist -m normal -o hdisk0 hdisk2  --> create a new bootlist
# bosboot -a  -->  update the boot image information
# bootlist -m normal -o  --> verify the bootlist is correct

Saturday, April 14, 2007

Oracle import

I was asked by a colleague, how to import an oracle dump file, that was exported from customer production site without data. Someone may think that it is stupid to write about this trivial task. However it is not so simple. In order to provide support for production database, we sometime have to export customer database without data and then import the exported file containing only schema and store procedure into our developer sandbox for testing purpose. The problem is that when import, Oracle try to create table and allocate data segment on disk with the same size as in the production database. Our developer sandbox of couse does not have capacity as customer production machine, so the import process often fails. Solution to this problem is perform import process into 3 steps. In Step 1, we create table and index creation file using e.g.
$imp userid=system/manager@test file=exp-code.dmp full=yes indexfile=create-schema.sql
This will create create-schema.sql that contains tables and index creation commands. With little effort, using any text editor, we can modify this file to remove segment size parameter of each command and save it as create-schema-small.sql. In Step 2, we run modified create-schema-small.sql against test database to create tables and indexes
$sqlplus scott/tiger@test @create-schema-small.sql
In Step 3, we run normal import with ignore error option, so Oracle will create store procedures and others required metadata.
$imp userid=system/manager@test full=yes file=exp-code.dmp ignore=yes
After reading, other colleague points out that in Oracle 10g, Oracle provide other tools expdp and impdp that can handle the above mentioned problem.

Thursday, April 12, 2007

Soft Coding

I have read the soft coding article recently. Based on my own experience I have a sympathy to the hard coding approach. However I think the problem is not about whether soft coding or hard coding, but programmers including myself try rigidly to follow the soft coding approach believing that it will result in more flexible code, which is not true in most cases.

Sunday, April 8, 2007

Using Regexp

I got a task to parse file consisting of SQL commands and various noisy lines including empty, comment and echo. I decided to use ruby String::scan to extract SQL commands from files. The only problem is how to write an correct regexp. I started with some test
entire=<<-EOF
create table A(id number)
/
create table B(id number)
/
EOF

entire.scan(/create table.*\//) #=>[]
I passed to String::scan a regexp that represents a String starting with 'create table' following by any number of characters and ending with '/'. But there is something wrong instead of
=> ["create table A(id number)\n/", "create table B(id number)\n/"]
I got a empty array
=>[]
I have looked at documentation, tried different alternatives without success. Then I picked the book Mastering Regular Expressions and read the chapter. It is immediately clear to me, instead of using '.' as any character, I should use [^\/] mean any character different from '/'. The correct usage of regexp is
entire.scan(/create table[^\/]*\//) 
#=> ["create table A(id number)\n/", "create table B(id number)\n/"]
In order to support multi-line and avoid case sensitive, I just add two options 'm' and 'i' to the regexp
entire.scan(/create table[^\/]*\//im) 

Monday, April 2, 2007

Using Ruby and Rails with Oracle database

1. Download ruby-oci8-VERSION-mswin32.rb 2. Install oci8 adapter e.g. on MS Windows
c:\ruby ruby-oci8-VERSION-mswin32.rb
3. Using with with Rails
ActiveRecord::Base.establish_connection(
 :adapter => "oci",
 :host => "sql_net_connect_string",
 :username => "foo",
 :password => "bar"
)

AIX varyon volume group in multi nodes environment

On environment with multi-nodes running AIX accessing single share fiber channel storage, I am facing a problem, if one node fails, I can not import volume group residing on that physical disk in an other surviving node, although physical volume owned by that node is accessible from surviving node. OS gives out a error can not access volume group descriptor. It make me crazy, because one reason, why I need expensive fiber channel storage is to have flexibility to access volume group of failure node from surviving node. It takes me a while to figure out how it works. When AIX activate volume group, it places a lock on corresponding physical volume, so other node can not activate this volume group. The varyon command always checks the physical volume and refuses to activate that volume group if it is locked by other. It does not matter if the locking node is still living or death. In order to release the lock, we should issue on locking node
varyon -b volume_group_name 
This '-b' flag breaks disk reservations on disks locked as a result of a normal varyonvg command. Because this flag only works on volume group that is already varied on, we should do it on a node that originally owns this volume group to make sure that if that node fails, other can activate the volume group.

Sunday, April 1, 2007

Writing an Use Story

Having Use Story is first step of software development cycle. How to effectively write an good, concise Use Story is challenging task of business analyst. I have found quite good guideline on that topic on Dan North What is Story

Sunday, March 18, 2007

Who will develop software in 10 years?

This is topic of the panel moderated by Martin Fowler on recent JAOO Conference. But the discussion goes beyond it to other interesting questions "How is it going to be done ?" and "Where it is going to be done?". The video of this panel is available on InfoQ website here. Opinions of panellists to the first question are software is still going to be developed by software developer in next 10 years. However tools, DSL will help non-software people i.e. domain experts more involving in the process such as configuring software or create domain model and using tool to generate software. This will make the distinction between application software developer and domain experts less obvious. As result of this, an idea to build a DSL rather than an application presented in Never Build an Application becomes more acceptable.

Saturday, March 17, 2007

My second job

In 1992, one friend introduced me to Notia, an finance consulting, auditor and software development company in Prague. Then I joined Notia as programmer. This was one of most important milestone in my professional career and Notia was my employer until 1996. I have worked for the company in many projects, playing different role, getting a lot of wonderful friends, learned many new things. My first team leader was Tran Duc Trung, who is now Chief Architect for NetBean at Sun Microsystem.

Saturday, March 10, 2007

An answer to PragDave Quick Ruby Quiz

Dave Thomas in Quick Ruby Quiz asked how to call method say_hello in
class Fred
  class << self
    def self.say_hello
      puts "Hi!"
    end
  end
end
I have figured out one of possible way is
klass = class << Fred; self; end
klass.singleton_methods #=> ["constants","nesting",
                        # "say_hello"]
klass.say_hello #Hi!

Thursday, March 8, 2007

Using Ruby flatten and to_a

class Processor
  def initialize arg
  @arg = arg
  end
 def process
  puts @arg
 end
end

def run_single(processor)
 processor.process
end

def run(processors)
 processors.each{|p| p.process}
end

run_single(Processor.new 'Hello')
run([Processor.new 'Hello',Processor.new 'World'])
In above example, we need to define two methods run_single taking a processor and run taking array of processors. To make it simple, we can remove run_single method just call
run([Processor.new 'Hello']) 
in case of single processor. However passing a single element array seems to be not natural, by using flatten or to_a we can create a method that accept both element and array of element as parameter
def run(processor)
 [processor].flatten.each{|p| p.process }
end
or other possible way is
def run(processor)
 processor.to_a.each{|p| p.process }
end
then we can do
run(Processor.new 'Hello')
run([Processor.new 'Hello',Processor.new 'World'])

Tuesday, February 20, 2007

Ruby's DSL implementation pattern

DSLs are designed to solve a particular kind of problem. Implementation DSLs as internal DSLs in Ruby is getting popular. Jim Freeze in his article Creating DSLs with Ruby use "Interpret" pattern to implement DSL. According the article a problem will be solved by using instance of a Class Machine. The Machine has class method load that create an instance of the Class Machine and load a file containing machine's instructions writen in DSL. The Machine also has instance method process, that run loaded instructions with specified data. A Ruby implementation can be as follow
class Machine
  def self.load(filename)
    machine = Machine.new
    machine.instance_eval(File.read(filename), 
      filename)
    machine
  end

  def process(*arg)
  #...
  end
end
Using this pattern, in The ruby implementation of an example in Martin Fowler's Language Workbenches article the Reader class can be modified as follows
class Reader
    #...

    def self.load dsl_file_name
        reader = Reader.new
        reader.instance_eval(File.read(dsl_file_name), 
          dsl_file_name)
        reader
    end

    def process data_file_name
        File.open(data_file_name,'r') do |file|
            while line = file.gets
                process_line line
            end
        end
    end

    #...

    def mapping type_code, type, &block
        @strategies[type_code] =
            ReaderStrategy.new type_code, type, &block
    end

end
#dsl.txt
mapping('SVCL', ServiceCall) do
  extract 4..18, 'customer_name'
  extract 19..23, 'customer_ID'
  extract 24..27, 'call_type_code'
  extract 28..35, 'date_of_call_string'
end
mapping('USGE', Usage) do
  extract 9..22, 'customer_name'
  extract 4..8, 'customer_ID'
  extract 30..30, 'cycle'
  extract 31..36, 'read_date'
end
#load_dsl.rb
require 'test/unit'
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader_strategy')
class TestLoadDsl < Test::Unit::TestCase
    def test_read_file_load_dsl
        dsl_file_name =  File.join(File.dirname(__FILE__),
            'dsl.txt')
        reader = Reader.load dsl_file_name

        data_file_name = File.join(File.dirname(__FILE__),
            'sample.txt')
        reader.process data_file_name

        assert_equal 4, reader.result.size
    end
end

Monday, February 19, 2007

Ruby and DSL

Googling on Internet, I found few interested sources of information of how to implements DSL on top of Ruby language.
Creating DSLs with Ruby
The Way of Meta
Writing Domain Specific Languages

Sunday, February 18, 2007

ERP Application Service Providers

During Tet Holiday, I have time to read the Friedman's Book "The World Is Flat: A Brief History of the Twenty-first Century " that is given to me by a friend. One chaper of the book mention about Salesforce, a company that provides CRM software as service via Internet at very low cost. (Software as a Service) SaaS is not new, the idea rooted from 60, 70 year of last century under different name such as service bureau, utilities computing, etc. I think, using ERP as service is very attractive for small, mid-size companies. Searching on Google, I found the following companies (ASP) offering ERP sofware as service 24SevenOffice NetSuite SalesForce TwinField Oracle CRM On Demand RightNow Technologies Fee of service is different from company to company ranging from 40 to 100 USD per user per month.

Saturday, February 17, 2007

White Paper về ngành CNTT Việt Nam của GS TS John Vũ

Một người bạn gửi cho Tôi tài liệu nhan đề "Ngành CNTT Việt Nam phải làm gì để thành công trên thị trường thế giới?" của John Vũ. Do đây là chủ đề được nhiều người từ các nhà hoạch định chính sách, các nhà đầu tư, các nhà quản lý, cho đến các kỹ sư phần mềm quan tâm, Tôi đưa nguyên văn dưới đây để mọi người tham khảo.

Hội Tin Học TP.HCM (HCA) nhận được nội dung Bạch Thư (White Paper) về ngành công nghiệp CNTT Việt Nam của GS. TS John Vũ - Viện sĩ Viện Hàn Lâm Software Engineering Institute (SEI) thuộc Carnegie Mellon University (CMU); Kỹ sư Trưởng Trung Tâm CNTT của Tập Đoàn Boeing. Qua nội dung của Bạch Thư, người đọc không chỉ tiếp thu thông điệp từ Boeing về những khuyến nghị mà ngành công nghiệp CNTT Việt Nam cần thực hiện mà còn cảm nhận được tình cảm của một trong những chuyên gia Việt Kiều CNTT hàng đầu thề giới gởi đến cộng đồng CNTT Việt Nam, để cùng suy nghĩ cho một ước mơ sử dụng CNTT đưa đất nước vượt thoát đói nghèo, nắm bắt được thời cơ lịch sử của CNTT Việt nam trong bối cảnh cạnh tranh toàn cầu. Hội Tin Học TP.HCM (HCA) tạm dịch nội dung của Bạch Thư và mong nhận được những ý kiến trao đổi của các Anh Chị chuyên gia và doanh nghiệp trong cộng đồng CNTT Việt Nam:
Ngành CNTT Việt Nam phải làm gì để thành công trên thị trường thế giới?
Bạch Thư
Người thực hiện: John Vu – Viện sĩ Viện Hàn Lâm - Carnegie Mellon Univeristy-CMU; Kỹ sư trưởng TT CNTT tập đoàn Boeing 09/2006 Dựa trên những thông tin được cung cấp bởi Hội Tin học TP.HCM (HCA), trang web của rất nhiều công ty cũng như những trao đổi với các lãnh đạo doanh nghiệp CNTT trong suốt chuyến đi Việt Nam, tôi đã thực hiện báo cáo này, đưa ra một cái nhìn tổng quát về ngành CNTT Việt Nam. Dựa trên những kinh nghiệm mà tôi đã trải nghiệm tại Ấn Độ, Trung Quốc, Nam Triều Tiên và Châu Âu, tôi đã đúc kết được một vài vấn đề then chốt nhằm giúp Việt Nam thành công trên lĩnh vực CNTT toàn cầu. Tuy nhiên, báo cáo này cũng chỉ là những quan sát và nhận xét chủ quan của riêng cá nhân tôi, còn nhiều thiếu sót do không đủ thời gian và nỗ lực để thu thập đầy đủ dữ liệu và các thông tin quan trọng. Xét về khía cạnh nào đó, tôi tin chắc rằng báo cáo này có thể giúp Việt Nam tạo ra những lối đi riêng trong việc tập trung vào một vài hoạt động trong năm đầu tiên; tuy nhiên, những hành động có tính chất toàn diện của các khuyến nghị là cần thiết để làm thay đổi ngành công nghiệp CNTT Việt Nam và cho phép tham gia kinh doanh toàn cầu.
1) Quy mô là một vấn đề:
Hầu hết các công ty CNTT tại Việt Nam đều là công ty nhỏ (số nhân sự dưới 50 người). Đây chính là nguyên nhân gây ra những khó khăn, cản trở trong việc hội nhập với thế giới. Nếu nhân sự của công ty bạn đủ mạnh, các đối tác nước ngoài sẽ tin rằng họ đang hợp tác với một công ty đủ sức đương đầu với những rủi ro, luôn có đội ngũ nhân viên chuyên nghiệp, có thể thực hiện được những mong muốn của họ và dĩ nhiên, họ sẽ giữ mối quan hệ hợp tác lâu dài với công ty bạn. Ngoài việc liên doanh và sát nhập, một giải pháp khác là thành lập một liên kết chặt chẽ giữa một số công ty CNTT nhưng vẫn giữ tính cách độc lập của các thành viên (consortium), bao gồm những công ty nhỏ để tập trung nguồn nhân lực cùng thực hiện các dự án chung. Lãnh đạo của consortium (có thể là Khu Công nghệ (CN) Cao sẽ đóng vai trò là nhà đại diện để giao dịch với khách hàng. Consortium có một thực thể pháp l‎ý riêng và tiếp cận thị trường qua một thương hiệu riêng. Dĩ nhiên, các công ty CNTT trong consortium phải có khả năng làm việc độc lập và hiệu quả để tối thiểu hoá những rủi ro cho khách hàng. Để không ngừng phát triển và mở rộng thị trường quốc tế, doanh nghiệp CNTT tại Việt Nam phải chuyển đổi hình thức “kinh doanh gia đình” sang hình thức hoạt động chuyên nghiệp và cần tập trung vào những thị phần chuyên biệt. Mặt khác, các doanh nghiệp cần cải tiến quy trình quản l‎ý, đặc biệt là việc lập các báo cáo tài chính và tín dụng. Không có một hệ thống quản l‎ý và tài chính tốt, doanh nghiệp Việt Nam rất khó mà có được chỗ đứng trong thị trường quốc tế. Hơn nữa, doanh nghiệp Việt Nam cũng cần nắm rõ những thị trường tiềm năng, nắm bắt thị hiếu đối tác và đầu tư vào lĩnh vực nghiên cứu và phát triển (R&D) để đủ sức cạnh tranh với các đối thủ.
Khuyến nghị:
• Nghiên cứu kỹ lưỡng về khả năng tạo ra một consortium CNTT thông qua Khu CN cao. Khu CN cao đóng vai trò như một thực thể pháp lý độc lập trong việc thương thảo với đối tác.
• Để làm việc quốc tế, ta nên tạo ra thương hiệu chung giữa 20-30 công ty nhỏ hơn là các công ty cá thể.
• Đầu tư vào lĩnh vực R&D để nhận biết những sở trường chủ yếu của ngành công nghiệp CNTT và phát triển các cơ hội tương lai.
• Tập trung vào việc cải tiến cơ cấu quản lý, tài chính, kế toán và cơ sở hạ tầng để nâng tầm kinh doanh toàn cầu.
• Nghiên cứu xu hướng thị trường để xác định và triển khai những thị phần chuyên biệt trước khi phát triển theo diện rộng.
• Tăng cường hoạt động tiếp thị để xây dựng hình ảnh một Việt Nam thực sự là một địa điểm kinh doanh.
• Đề nghị sự hỗ trợ chuyên môn từ Boeing để nhận diện môi trường kinh doanh CNTT hiện nay và nắm bắt những cơ hội trong tương lai.
2) Dịch vụ là một vấn đề:
Dựa trên “Báo cáo Toàn cảnh CNTT-TT Việt Nam” của Hội Tin học TP.HCM (HCA), ngành công nghiêp CNTT Việt nam dường như tập trung nhiều vào các hoạt động như lắp ráp máy tính, kinh doanh phần cứng và cung cấp các dịch vụ internet. Đây là những lĩnh vực có tính không ổn định rất cao do sự cạnh tranh từ các doanh nghiệp được tổ chức tốt như Lenovo, IBM, Dell, HP and AOL, đặc biệt là khi Việt Nam gia nhập Tổ chức Thương mại Thế giới (WTO). Sẽ tốt hơn và có nhiều lợi ích hơn nếu ngành công nghiệp CNTT Việt Nam tập trung vào ngành công nghiệp dịch vụ; như gia công phần mềm, gia công dịch vụ trong qui trình quản lý (Business Process Outsourcing - BPO) và gia công lưu trữ dữ liệu thông tin (Media Storage Outsourcing - MSO) là những lĩnh vực có thể sinh lợi rất nhiều cũng như tạo ra nhiều cơ hội việc làm hơn là ngành công nghiệp sản phẩm hiện nay.
Ngành công nghiệp gia công phần mềm Việt Nam vẫn còn rất non trẻ với nhiều công ty chỉ tập trung vào một phần nhỏ trong chu trình phát triển phần mềm như nhập liệu, testing và mã hóa, trong khi có rất ít doanh nghiệp thể hiện năng lực phát triển ứng dụng, quản trị dự án, kiến trúc hệ thống, tích hợp hệ thống, quản trị cơ sở dữ liệu hoặc phân tích quy trình kinh doanh. Nguyên nhân cũng có thể là do hệ thống giáo dục hiện nay vẫn còn ảnh hưởng từ truyền thống Đông Âu – chuyên về đào tạo lập trình hơn là phân tích, thiết kế và phát triển các ứng dụng, các kỹ năng quản l‎ý vốn là thế mạnh của truyền thống đào tạo giảng dạy tại Mỹ.
Khuyến nghị:
• Tiếp thu cách tiếp cận mới về phát triển phần mềm và tập trung vào toàn bộ chu trình phát triển sản phẩm thay vì chỉ triển khai một phần nhỏ trong chu trình.
• Chuyển ngành CNTT Việt Nam từ khuynh hướng nghiêng về sản phẩm sang khuynh hướng nghiêng về dịch vụ.
• Xây dựng kế hoạch quôc gia, hoặt ít nhất là kế hoạch vùng để tập trung vào công nghiệp gia công.
• Hợp tác với các trường đại học nhằm đào tạo nhiều hơn nữa nguồn nhân lực tập trung vào quy trình phần mềm tổng thể và một số kỹ năng chuyên biệt hiện đang thiếu hụt trên thế giới hiện nay.
• Đề nghị sự hỗ trợ về chuyên môn của Boeing nhằm nhận thức đầy đủ về công nghiệp gia công CNTT và nắm bắt được các cơ hội thị trường.
3)Năng lực là một vấn đề:
Có một sự cường điệu khi giới thiệu ưu thế của ngành CNTT Việt Nam là chi phí nhân công thấp trong việc thay thế Ấn Độ và Trung Quốc trong thị trường CNTT thế giới. Ngay cả khi có một giá nhân công thấp hơn, thì nếu chỉ có giá thấp cũng không tạo ra một yếu tố chính cho sự lựa chọn của đối tác. Nhận được đơn hàng mới chỉ là giai đoạn ban đầu trong khi tạo được sự hài lòng cho khách hàng mới là tất cả công việc. Nếu khách hàng nhận ra việc thiếu năng lực của mình thì rất khó giữ được sự hợp tác lâu dài. Hầu hết các doanh nghiệp trên thế giới đều rất cẩn trọng trong việc chọn lựa nhà cung ứng thông qua hệ thống tiêu chuẩn chọn lựa khắt khe có được từ những kinh nghiệm tại những thị trường đã được định hình như Ấn Độ.
Tôi thiết tha khuyến cáo các doanh nghiệp CNTT tại Việt nam nên xác định vị thế của mình dựa trên năng lực chuyên môn hơn là chỉ dựa vào giá thấp. Năng lực chỉ được công nhận dựa trên một hệ thống giáo dục và đào tạo tiên tiến; điều này cần rất nhiều thời gian và công sức. Sự phóng đại năng lực chỉ làm tăng tỉ lệ thất bại hoặc đưa đến những dự án không đạt yêu cầu trong mắt của đối tác. Điều này làm cho chúng ta đánh mất sự tín nhiệm và mất cả những cơ hội hợp tác tiếp theo. Tốt hơn cả là nên bắt đầu bằng năng lực thực sự và xây dựng sự tín nhiệm nơi khách hàng, khi đã tạo nên mối quan hệ tốt và năng lực đã vững vàng thì việc kinh doanh sẽ phát triển nhanh chóng.
Khuyến nghị:
• Đặt kế hoạch phát triển kỹ năng nghiệp vụ hơn là cách đưa ra giá thấp.
• Hợp tác với các trường đại học để đào tạo các kỹ năng như bảo mật, khai thác dữ liệu, quản l‎ý dự án, kiến trúc phần mềm, tích hợp hệ thống v.v…
• Tập trung vào việc cải tiến kỹ năng và năng lực cũng như xác định những kẽ hở thị trường mà Việt Nam có thể chiếm lĩnh trong hiện tại và tương lai.
• Xây dựng mối quan hệ tốt với khách hàng qua việc thực hiện công việc hơn là giá thấp.
• Phân tích thị trường nhằm nhận diện các khả năng phát triển.
• Đề nghị sự hỗ trợ của Boeing trong việc cải tiến giáo dục và đào tạo.
4) Vấn đề về trình độ quản lý vững vàng và việc đạt được chính thức chứng chỉ chất lượng quản lý :
Các khách hàng quốc tế trông đợi nhiều vào trình độ quản lý và chất lượng công việc từ các nhà gia công CNTT. Ấn Độ là quốc gia gia công chiếm lĩnh được vị trí hàng đầu, Việt nam cũng nên đạt đến vị trí của các công ty Ấn độ hoặc sẽ trở thành nhà cung cấp hạng hai hay hạng ba, chỉ nhận được các công việc có lợi nhuận thấp như nhập liệu hoặc thử nghiệm phần mềm.
Chứng chỉ quản lý chất lượng CMMI (Capability Maturity Model Integrated) được phát triển bởi Viện Công Nghệ Phần Mềm (Software Engineering Institute - SEI) của Carnegie Mellon University (CMU), được chấp nhận bởi khách hàng trên toàn thế giới như một tiêu chuẩn bảo đảm cho chất lượng phát triển phần mềm. Các công ty Việt Nam cần đạt được các trình độ cao của CMMI (cấp 4 và 5).
Đối với các khách hàng quốc tế, việc tìm kiếm các nhà cung cấp mới đem đến nhiều rủi ro, nhiều người trong số họ không thích có thêm những nhà cung cấp mới. Một chứng chỉ quản lý chất lượng được công nhận bởi một cơ quan chứng thực độc lập giúp họ giảm bớt những rủi ro. Có được chứng chỉ chính thức CMMI là điểm tạo sự khác biệt chính trong hoạt động gia công phần mềm. Để cạnh tranh toàn cầu, tất cả các doanh nghiệp CNTT Việt Nam cần phải đạt được chứng chỉ CMMI từ các nguồn được công nhận.
Hiện nay, có nhiều chứng chỉ chất lượng “giống CMMI” được cấp bởi những nhà tư vấn ở một số quốc gia nhưng không được tổ chức quốc tế chính thức công nhận. Việc nhận các chứng chỉ như vậy có thể gây ra sự nhầm lẫn đem đến sự tổn hại về uy tín của doanh nghiệp Việt Nam. Chứng chỉ CMMI của Mỹ đòi hỏi sự chứng thực của cơ quan đánh giá được SEI uỷ nhiệm hợp pháp. Danh sách các đơn vị được cấp chứng chỉ CMMI được SEI công bố để bảo đảm tính hợp pháp của qui trình chứng thực. Hầu hết khách hàng quốc tế đều tham khảo danh sách cấp chứng chỉ CMMI của SEI để thẩm định tính xác thực về chứng chỉ CMMI của những ứng viên cung cấp dịch vụ gia công cho họ.
Khuyến nghị:
• Các công ty CNTT Việt Nam nên nhanh chóng đạt được chứng chỉ CMMI từ nguồn chính thức.
• Dự trù ngân sách cho việc đạt chứng chỉ CMMI.
• Tạo sự đồng thuận trong tất cả nhân viên xem việc cam kết chất lượng là phương cách kinh doanh.
• Tập trung vào chất lượng và hiệu quả để tạo nên điểm khác biệt của doanh nghiệp.
• Quảng bá kết quả của việc nhận chứng chỉ CMMI như là một phần việc marketing.
• Đề nghị sự hỗ trợ của Boeing trong việc đào tạo và cấp chứng chỉ CMMI.
5. Vấn đề thử thách mới, kỹ năng mới: Là một thử thách rất lớn cho Việt Nam khi đối mặt với những đối thủ hàng đầu như Trung Quốc, Ấn Độ. Tuy vậy, với việc đào tạo đúng và tiếp cận tốt, CNTT Việt Nam có thể cạnh tranh trực tiếp với những đối thủ lớn này trong thị trường toàn cầu. Việt Nam có những ưu và nhược điểm riêng; nên tập trung vào những gì mình làm được hơn là theo những việc mà Trung Quốc và Ấn Độ đang làm. Để có thể chiến thắng nên thay đổi quan điểm như chi phí thấp và khả năng cao.
Hiện nay cả Trung Quốc và Ấn Đô đều bị ảnh hưởng của việc thiếu hụt trầm trọng nguồn nhân lực kỹ năng cao và họ cố gắng giải quyết vấn đề bằng cách đào tạo ồ ạt số lượng lớn người làm CNTT. Điều này dẫn đến việc giảm chất lượng của nguồn nhân lực. Đây là cơ hội tốt cho Việt Nam để cạnh tranh bằng cách cung cấp nguồn nhân lực kỹ năng cao qua những chương trình giáo dục và dạy nghề nghiêm chỉnh.
Ngành công nghiệp CNTT thay đổi nhanh chóng, việc hiểu rõ tiến trình và xu hướng phát triển sẽ giúp Việt Nam điều chỉnh hướng đi và tái họach định để bảo đảm kẽ hở thị trường hơn là đi theo những việc người khác đã làm. Xu hướng hiện nay xem trọng giá trị công việc và mối quan hệ hơn là nguồn nhân lực giá rẻ. Hầu hết các phần mềm đang trở thành hệ thống hội tụ mạng lưới, ngày càng phức tạp; đòi hỏi những kỹ năng thành thạo về cấu trúc hệ thống, thiết kế, tích hợp hơn là lập trình hay testing. Khuynh hướng này không có nghĩa là sẽ không còn việc cung ứng nhân lực giá rẻ nhưng ngành công nghiệp ngày càng mở ra nhiều cơ hội cho những quốc gia nào có thể cung cấp được những kỹ năng mới cho khách hàng.
Khuyến nghị:
• Tiến hành nghiên cứu thị trường để nhận diện những kỹ năng, những khả năng mới - đặc biệt tránh những kỹ năng thông thường như lập trình, testing mà nước nào cũng có …
• Thu thập và phát triển những chương trình đào tạo các kỹ năng chuyên sâu - đặc biệt trong quản lý dự án, phân tích yêu cầu kinh doanh, kiến trúc hệ thống, tích hợp hệ thống, quản trị toàn bộ, thiết kế, xây dựng hệ thống…
• Đào tạo những kỹ năng mới cho nhân viên.
• Đề nghị Boeing hỗ trợ các chương trình đào tạo kỹ năng mới từ các trường đại học Mỹ.
6. Vấn đề truyền thông:
Kinh doanh toàn cầu cần kỹ năng giao tiếp trong nhiều ngôn ngữ nhưng tiếng Anh vẫn quan trọng nhất. Doanh nghiệp CNTT Việt Nam cần đào tạo nhân viên về giao tiếp tiếng Anh và hiểu về văn hóa của khách hàng đối với từng nước.
Để giải quyết vấn đề này, cần đến sự trợ giúp của ngoại kiều hoặc của Việt kiều làm người đại diện. Trong môi trường kinh doanh toàn cầu, nên có bộ phận quản lý tại chỗ gồm những người am hiểu văn hóa và tập quán kinh doanh bản địa. Ước tính có khoảng một triệu người Việt Nam tại nước ngoài có khả năng như vậy. Cộng đồng này hầu hết có thể nói hai ngôn ngữ và thường hiểu văn hóa thị trường nơi mà họ lớn lên.
Khuyến nghị:
• Thu thập những chương trình dạy Anh văn cho nhân viên CNTT.
• Thuê nhân viên địa phương hoặc Việt kiều làm đại diện ở mỗi thị trường.
• Tập trung vào việc hiểu rõ văn hóa kinh doanh của khách hàng.
• Thu thập các chương trình đào tạo Anh ngữ cho các khu công nghiệp kỹ thuật cao và các trường đại học.
• Đề nghị Boeing hỗ trợ việc hợp tác với các Học viện và trường đại học Mỹ.
7) Vấn đề về đối tác và liên minh:
Tất cả những công ty CNTT thành công đều có đối tác tại những lĩnh vực nằm ngoài khả năng của họ. Các công ty CNTT Việt Nam cần liên kết với những đối tác khác và tạo ra những liên minh hoạt động trong những lĩnh vực nhất đinh nhằm xác định thị trường theo ngành dọc. Những doanh nghiệp Việt Nam nên giao cho các đơn vị khác cung ứng cho mình những dịch vụ bên ngoài dịch vụ chính và hình thành các mối quan hệ tin cậy với khách hàng. Khu công nghiệp cao có thể là nơi được cân nhắc trước tiên để tạo lập mối quan hệ đối tác hoặc liên minh lẫn nhau. Một cách cơ bản là một thực thể liên kết nhiều công ty sẽ tạo nên một sức mạnh lớn trong thị truờng cạnh tranh gay gắt hiện nay.
Khuyến nghị:
• Thăm dò khả năng thành lập mối quan hệ đối tác và liên minh.
• Hình thành thực thể liên kết consortium lớn để quản lý toàn bộ chu trình hoạt động.
• Nghiên cứu các chủ trương chính sách nhà nước các cấp để xúc tiến thành lập consortium.
• Xác định, kết nối và đo lường những giá trị gia tăng của từng liên minh.
• Hợp thức hoá việc uỷ quyền cho Khu công nghiệp cao như một thực thể đại diện và thương hiệu duy nhất.
• Đề nghị Boeing hỗ trợ xây dựng thương hiệu cho Khu Công nghệ cao.
• Đề nghị Boeing hỗ trợ việc đào tạo cho các nhà quản lý Khu Công nghệ cao từ các trường Đại học và các trung tâm đào tạo ở Mỹ.
8) Vấn đề tiếp thị và quảng cáo: Cho dù là ngành công nghiệp CNTT Việt nam phát triển rất nhanh trong vài năm qua, nhưng hầu như tình hình này chưa được biết đến trên bình diện kinh doanh toàn cầu. Nếu khách hàng không biết gì về Việt Nam thì tại sao họ phải làm kinh doanh tại đây? Điều quan trọng bây giờ là Việt Nam cần nỗ lực sử dụng các chiến dịch kinh doanh để chào hàng cho được “CNTT Việt Nam”. Rất khó cạnh tranh với các đối thủ được tổ chức tốt như Ấn Độ, Trung Quốc . Nếu chỉ có giá thấp thì sẽ nhận được rất ít đề nghị có giá trị. Hiện nay hầu hết các doanh nghiệp phương tây giao gia công không coi vấn đề chi phí là chuyện chính yếu mà họ đang tìm kiếm những nguồn cung ứng các dịch vụ có giá trị như hệ chuyên gia và tiếp cận thị trường địa phương.
Khuyến nghị: Việt Nam cần xác định vị trí của ngành công nghiệp CNTT vào:
* chất lượng và hiệu quả (được chứng nhận bởi tiêu chuẩn CMMI).
* cơ sở hạ tầng ổn định để có thể chuyển giao các dịch vụ cho khách hàng nhanh hơn, tốt hơn và đáng tin cậy hơn.
* xây dựng các kỹ năng chuyên biệt.
* đầu tư phù hợp cho hạ tầng để có thể kinh doanh tốt.
* thân cận với các thị trường Châu Á Thái Bình Dương.
* bảo đảm sự ổn định chính trị và an ninh xã hội.
* thu hút doanh nhân và khách du lịch đến Việt nam.
Kết luận:
Những thông tin trong bạch thư này được tôi thu nhận trong chuyến công tác vừa qua ở Việt Nam, có tính chất chủ quan hơn là dựa trên số liệu nghiên cứu khách quan. Tôi tin chắc rằng ngành công nghiệp CNTT Việt Nam cần nghiên cứu rộng hơn và hành động. Những khuyến nghị của tôi giới hạn trong phạm vi quan sát cá nhân với nhận thức đây chỉ là những hỗ trợ ban đầu của Boeing giúp Việt Nam cải thiện hệ thống giáo dục để xây dựng ngành khoa học không gian và ngành CNTT - TT mạnh mẽ; được nhận biết trên thị trường quốc tế và có khả năng cạnh tranh toàn cầu.
(Nguồn: HCA)

Thursday, February 15, 2007

Chúc mừng năm mới Đinh Hợi

Bức tranh Hoa Đào (Peach Blossom) này là của họa sĩ đương đại Trung Quốc DU YINGQIANG.

Tuesday, February 13, 2007

Convert Proc object to a block

Ruby methods like yield or instance_eval accept only block not Proc object. In order to use instance_eval in inner method, we need to convert Proc to block, the syntax is pretty simple just precede Proc object with ampersand.
def m1 &block
  m2 &block
end

def m2 
 yield
end

m1 {puts "hello"} # hello

a = Proc.new {puts "world"}

m2 &a # world

def m3 block
  instance_eval &block
end

m3 a # world

Sunday, February 11, 2007

The ruby implementation of an example in Martin Fowler's Language Workbenches article

It take me 3 hours to figure out how to implement in ruby the example described in Language Workbenches. It is one of my effort to learn the ruby language. The implementation uses what Jamis Buck's in the article Writing Domain Specific Languages called Sandboxing Approach.
#file ./lib/data.rb
class ServiceCall
    attr_accessor :customer_name,:customer_ID,
          :call_type_code,:date_of_call_string
end
class Usage
    attr_accessor :customer_name,:customer_ID,
          :cycle,:read_date
end
#file ./lib/data_reader.rb
class Reader
    attr_accessor :result

    def initialize
        @result = []
        @strategies = {}
    end

    def process file_name
        File.open(file_name,'r') do |file|
            while line = file.gets
                process_line line
            end
        end
    end

    def process_line line
        return if is_blank(line) || is_comment(line)
        type_code = get_type_code(line)
        strategy = @strategies[type_code]
        msg_err = <<-END
            unable to find strategy for
            type_code #{type_code}
        END
        raise msg_err if nil==strategy
        @result << strategy.process(line)
    end

    def is_blank line
        line == ''
    end

    def is_comment line
        line[0..0] == '#'
    end

    def get_type_code line
        line[0..3]
    end

    def mapping type_code, type, &block
        @strategies[type_code] =
            ReaderStrategy.new type_code, type, &block
    end

end
#file ./lib/data_reader_strategy.rb
class ReaderStrategy
    attr_accessor :extractors
    
    def initialize type_code, type, &block
        @type_code, @type = type_code, type
        @extractors = []
        instance_eval &block if block_given?
    end

    def process line
        result = @type.new
        @extractors.each do |e|
            e.extract_field result, line
        end
        result
    end

    def extract from_to, field_name
        @extractors << FieldExtractor.new(from_to,
            field_name)
    end

end

class FieldExtractor
    attr_accessor :from_to, :field_name

    def initialize from_to, field_name
        @from_to, @field_name = from_to, field_name
    end

    def extract_field target, line
        target.instance_variable_set(inst_var_sym,
            line[@from_to])
    end

    def inst_var_sym
        result = '@' + @field_name
        result.to_sym
    end
end
#file ./test/sample.txt
#123456789012345678901234567890123456789012345678901234567890
SVCLFOWLER         10101MS0120050313.........................
SVCLHOHPE          10201DX0320050315........................
SVCLTWO           x10301MRP220050329..............................
USGE10301TWO          x50214..7050329...............................
#file ./test/test_data_reader.rb
require 'test/unit'
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader_strategy')
class TestReader < Test::Unit::TestCase
    def setup
        @reader = Reader.new()
    end

    def test_read_file
        @reader.mapping('SVCL', ServiceCall) do
            extract 4..18, 'customer_name'
            extract 19..23, 'customer_ID'
            extract 24..27, 'call_type_code'
            extract 28..35, 'date_of_call_string'
        end
        @reader.mapping('USGE', Usage) do
            extract 9..22, 'customer_name'
            extract 4..8, 'customer_ID'
            extract 30..30, 'cycle'
            extract 31..36, 'read_date'
        end

        file_name = File.join(File.dirname(__FILE__),
            'sample.txt')
        @reader.process(file_name)
        assert_equal 4, @reader.result.size
    end

    def test_is_blank
        assert @reader.is_blank('')
    end

    def test_is_comment
        assert @reader.is_comment('#1234')
    end

    def test_get_type_code
        @reader.mapping('SVCL', ServiceCall)
        assert_equal 'SVCL',
            @reader.get_type_code('SVCLFOWLER')
    end
end
#file ./test/test_data_reader_strategy.rb
require 'test/unit'
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data')
require File.join(File.dirname(__FILE__),
    '..', 'lib', 'data_reader_strategy')
class TestReaderStrategy < Test::Unit::TestCase
    def test_service_call
        strategy =  ReaderStrategy.new 'SVCL',
        ServiceCall do
            extract 4..18, 'customer_name'
        end
        assert_equal 1, strategy.extractors.size

        result = strategy.process('SVCLFOWLER')
        assert_equal ServiceCall, result.class
        assert_equal 'FOWLER', result.customer_name
    end

    def test_usage_call
        strategy =  ReaderStrategy.new 'USGE',
        Usage do
            extract 9..22, 'customer_name'
        end
        assert_equal 1, strategy.extractors.size

        result = strategy.process('USGE10301TWO')
        assert_equal Usage, result.class
        assert_equal 'TWO', result.customer_name
    end

end

Tuesday, January 30, 2007

My second child

His name is Lê Hoàng, he is now more than three year old and he loves car toy.

Do 'nt criticize the customer

Today I did very bad thing. I did criticize our customer for something, that I think they should not do. The tone I used may cause a problem in our working relationship. Rethinking about it, I recognized that there are many better options with the same effect than criticizing. People do care about tone and the way you express your message. With the customer, we should rather propose than criticize, use more informal and less formal way. With our staff, we should give more recommendation and less command.

My first job as programmer

When people are getting older, they tend to lost the past memory. I am not an exception. That is a reason (just to keep the memory) why I want write about my past professional experiences. My career has started quite early in 1991, when I was in the second year at Mathematic and Physic Faculty of Charles University in Prague. At that time a friend of my recommended me a part time work for Metasoft, a software company doing customized software for small enterprises. My task is to customize a application software that will support operation of an accommondation agency. The propgram is pretty simple, the agency has a list of apartments, house and vila for renting. The question, they are intereted is if some houses, apartments or vila of requested capacity are available for a particular period. The program has been writen in Clipper programing environment (simmilar foxpro) on MS DOS.

Sunday, January 28, 2007

Ruby plugin for IntellijIDEA

My favorite IDE, IntellijIDEA has finally released workable ruby plugin. I hope that missing features as code completion and refactoring will be added. This is first post, I has uploaded a picture. After playing with the ruby plugin, I have discovered that code certain completion works when using key combination ctl+alt+shift+space.

Saturday, January 27, 2007

Variable-length argument list

Ruby allows us to define a method with variable-length argument list by placing asterisk before array argument. When we call this method, arguments are placed as normal separated by colon but inside the method we got an array of arguments.
def varargs(*args)
  args.each {|arg| puts arg}
end

varargs()                # 
varargs('arg1')          # arg1
varargs('arg1', 'arg2')  # arg1 \n arg2

We can also do reversely, which mean to pass an array as parameter when calling a method and expand array inside the method.

def one(arg)
  puts "one argument: #{arg}"
end

def two(arg1, arg2)
  puts "two arguments: #{arg1}, #{arg2}"
end

def three(arg1, arg2, arg3)
  puts "three arguments: #{arg1}, #{arg2}, #{arg3}"
end

def call(method,*args)
  send(method,*args)  
end

call(:one,'1')                  # one argument: 1
call(:two,'1', '2')             # two arguments: 1,2
call(:three,'1', '2', '3')        # three arguments: 1,2,3

Sunday, January 21, 2007

Câu lạc bộ những người bạn của CSE

Trong một cuộc nói chuyện của Tôi với Anh Nguyễn Việt Bắc, anh Bắc bảo Tôi đại loại như thế này "đi đâu cũng gặp người trước từng làm CSE, mấy hôm trước gặp mấy cậu làm FPT, hỏi câu trước, câu sau hóa ra trước làm CSE". Tôi nảy ra ý định tạo 1 trang web liệt kê danh sách các nhân viên/cộng tác viên từng hoặc đang làm việc, thực tập tại CSE, với mục đích ghi nhận sự phát triển và thành đạt của họ trong xã hội, chia sẻ kinh nghiệm trong công việc, cuộc sống cũng như các cơ hội hợp tác. Hy vọng ý tưởng này sẽ được hưởng ứng, nếu không thì ai đó cũng nên tạo 1 trang web về những người ghét của CSE chăng ? Đây là blog đầu tiên tôi thử viết bằng tiếng Việt. Nó cũng không khó như Tôi tưởng, chỉ cần Windows OS, Unikey và Firefox. Khi không có điều kiện kết nối Windows trực tiếp vào Internet, bạn Tôi Anh Khôi, nghĩ ra cách, trước tiên viết tiếng việt trên Windows bằng UltraEdit, lưu dưới dạng UTF8, upload file vừa viết lên Unix, trên Unix mở file nói trên bằng firefox, copy nội dung, paste vào blog window khi post. Mới nhìn có vẻ rối rắm nhưng khi làm cũng khá đơn giản.

Saturday, January 20, 2007

Kick off your software project as soon as possible

Frederick Brooks in The Mythical Man-Month said that "The bearing of a child takes nine months, no matter how many women are assigned. Many software tasks have this characteristic because of the sequential nature of debugging". The implication is in order to meet schedule, we should kick off a software project as soon as possible (perhap before a contract is signed) and within the project we should start as many tasks as possible and at earliest possible time.

Sunday, January 7, 2007

Ruby singleton class

In ruby world singleton class is term used frequently to describe something that is in java world called anonymous class. The term is sometime very confusing. I have seen this technique being used to extend class's behavior (as instance of Class). Suppose that we need to define a class instance variable the variable associated with the class (different from class variable, which is global variable)
class Foo
end
class Foo
  class << self
    attr_accessor :instances
  end
end
the equivalent variant of above code is
class Foo
end
class_foo = Foo
class << class_foo
    attr_accessor :instances
end
now do some test
Foo.instances =[] #=>[]
Foo.instance_variables #=>[@instances]
Foo.class_variables #=>[]
Foo.instances << Foo.new #=> [#<Foo:0x8241cbc>]
class Foo
  @@total = 0
end
Foo.class_variables #=>["@@total"]
The great tutorial about ruby singleton class can be found here

JRuby Going Camping Tutorial

Blog application does not work as per instructions described in JRuby Going Camping Tutorial. There are two reasons 1)latest JRuby version 0.9.2 probaly has bugs and 2)latest vesrion Camping 1.5 use un-usual ruby feature that is un-supported in JRuby. To make it work we should use JRuby version 0.9.1 and Camping version 1.4.2. The installation process for MS Windows is below 1. download,install JRuby version 0.9.1 and set JRUBY_HOME to installed directory e.g.
set JRUBY_HOME=d:\jruby-0.9.1
2. download and install MySQL into e.g.
c:\Program Files\MySQL\
3. download install MySQL JDBC and set CLASSPATH to MySQL JDBC driver e.g.
set CLASSPATH=c:\Program Files\MySQL\MySQL Server 
5.0\jdbc\mysql-connector-java-5.0.4-bin.jar
3. install camping version 1.4.2
%JRUBY_HOME%\bin\gem.bat install camping --version="1.4.2" 
--no-ri --no-rdoc --include-dependencies
4. install ActiveRecord-JDBC
%JRUBY_HOME%\bin\gem.bat install ActiveRecord-JDBC 
--no-ri --no-rdoc --include-dependencies
5. download file blog.rb from here into e.g.
d:\rubyapp\blog\
6. start mysql database manager
cd C:\Program Files\MySQL\MySQL Server 5.0\bin
mysqld.exe --console 
7. create blog database and blog user in mysql database
cd c:\Program Files\MySQL\MySQL Server 5.0\bin
mysqladmin.exe -u root create blog
mysql -u root
mysql>create user blog identified by 'blog';
mysql>grant all on blog.* to blog;
mysql>exit
mysql.exe --user=blog --password=blog -D blog
mysql>show tables
mysql>exit
8. run the blog application
d:\rubyapp\blog>%JRUBY_HOME%\bin\jruby 
%JRUBY_HOME%\bin\camping blog.rb

Saturday, January 6, 2007

Enterprise Rails

I have found two interesting documents that describe some experiences of using ruby on rails in a real enterprise project Rails Enterprise Ready from Jay Fields Rails for Enterprise from Rick Bradley and Charles Johnson

Managers vs. Leaders

John Kotter in "What Leaders Really Do." draws a sharp distinction between managers and leaders as follow Managers - Cope with Complexity: Plan and Budget, Organize and Staff, Track and Control Leaders - Cope with Change:Set Direction, Align People, Enable Motivation

Friday, January 5, 2007

Ruby's RI documentation

Ruby's RI program recognize '::' as class method and '#' or '.' as instance method File::dirname means dirname is class method of class File File#stat means stat is instance method of class File. So to get document of class method dirname of the class File, we type
huy@huy-desktop:~/support$ri File::dirname
we will get something like that
---------------------------------------------------------- File::dirname
     File.dirname(file_name ) -> dir_name
------------------------------------------------------------------------
     Returns all components of the filename given in _file_name_ except
     the last one. The filename must be formed using forward slashes
     (``+/+'') regardless of the separator used on the local file
     system.

        File.dirname("/home/gumby/work/ruby.rb")   #=> "/home/gumby/work"
To to get document of instance method stat of the class File, we type
huy@huy-desktop:~/support$ri File#stat
or other way is
huy@huy-desktop:~/support$ri File.stat
the result then is
------------------------------------------------------------- File#lstat
     file.lstat   =>  stat
------------------------------------------------------------------------
     Same as +IO#stat+, but does not follow the last symbolic link.
     Instead, reports on the link itself.

        File.symlink("testfile", "link2test")   #=> 0
        File.stat("testfile").size              #=> 66
        f = File.new("link2test")
        f.lstat.size                            #=> 8
        f.stat.size                             #=> 66

Wednesday, January 3, 2007

dos2unix

If your shell script looks well but does not work on linux machine, it probaly contains ^M at the end of each line because it may be created or modified using a dos/windows editor. To fix this problem run
dos2unix
command, which is OS/MAC to UNIX text file format converter available on linux.