#!/usr/bin/env ruby
def find_path gem_name
`gem list #{gem_name}` =~ /(.*)\s\((.*)\)/
version = $2.split(",")[0]
"#{Gem.default_dir}/gems/#{gem_name}-#{version}"
end
puts find_path ARGV[0]
Saturday, September 3, 2011
Find an installed Ruby Gem contents folder
Thursday, July 7, 2011
CouchDB with Jsonp
Download jquery.jsonp.js and ejs.js.
Templates "list.ejs"
test.html
Templates "list.ejs"
<ul>
<% $.each(list, function(i, element) {%>
<li><%=element%></li>
<% }); %>
</ul>
test.html
<!DOCTYPE html>
<html>
<head>
<title>CouchDB Demo</title>
<%= stylesheet_link_tag 'jquery-ui', 'develop_demo' %>
<%= javascript_include_tag :defaults, 'jquery.couch', 'jquery.jsonp-2.1.4.min', 'ejs' %>
<%= csrf_meta_tag %>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var url_all_dbs = "http://127.0.0.1:5984/_all_dbs";
function all_dbs() {
$.jsonp({
url: url_all_dbs + "?callback=?",
success: function(data) {
render_all_dbs(data);
}
});
}
function render_all_dbs(data) {
var template = new EJS({url: '/templates/list.ejs'})
var div_html = template.render({list: data});
$("#couch_all_dbs").html(div_html);
};
all_dbs();
});
</script>
</head>
<body>
<h1>Development Test</h1>
<div id="content">
Content...
<h1>all_dbs</h1>
<div id="couch_all_dbs"></div>
</div>
</body>
</html>
Thursday, March 24, 2011
HTML Audio Tag with Duration
Here is the code ..
<html>
<header>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
var audioElement = document.getElementById('audio');
audioElement.addEventListener("durationchange", function() {
var duration_div = document.getElementById('duration');
var duration = parseInt(audioElement.duration);
var min = parseInt(duration / 60);
var sec = duration % 60;
var str = "" + min + ":" + sec;
duration_div.innerHTML = str;
}, true);
audioElement.addEventListener("timeupdate", function() {
var current_div = document.getElementById('current');
var cur_time = parseInt(audioElement.currentTime);
var min = parseInt(cur_time / 60);
var sec = cur_time % 60;
var str = "" + min + ":" + sec;
current_div.innerHTML = str;
}, true);
});
</script>
</header>
<body>
<audio id="audio" controls preload="auto" autobuffer>
<source src="test.mp3" />
</audio>
<span id="current"></span> / <span id="duration"></span>
</body>
</html>
Sunday, February 27, 2011
Ruby's mDNS (dnssd)
I'd like to have Zero conf services. So, I was looking for those Discovery libraries and found this.. Let's try
Here is the service side.
And here is the client side..
3. Asynchronous Browse and Resolve
Enjoy!
Here is the service side.
require 'dnssd'
domains = []
enumerator = DNSSD.enumerate_domains do |reply|
domains << reply.domain
next if reply.flags.more_coming?
puts "Found domains:\n#{domains.join "\n"}"
break
end
DNSSD.register 'agent', '_agent._tcp', nil, 6464
puts "registered agent at 6464"
loop do
sleep 1
puts "agent running.."
end
And here is the client side..
require 'dnssd'
browser = DNSSD::Service.new
puts "Browsing for Agent service"
browser.browse '_agent._tcp' do |reply|
puts "Time: #{Time.new.to_f} reply: #{reply.fullname}"
puts reply
break
end
3. Asynchronous Browse and Resolve
require 'dnssd'
require 'socket'
browser = DNSSD::Service.new
puts "Browsing for Agent service"
# Make it Asynchronous ..
Thread.new do
browser.browse '_agent._tcp' do |reply|
puts "Time: #{Time.new.to_f} reply: #{reply.fullname}"
puts reply.inspect
puts reply.service_name
target = nil
resolver = DNSSD::Service.new
resolver.resolve reply do |r|
target = r.target
puts "#{r.name} on #{r.target}:#{r.port}"
# puts "\t#{r.text_record.inspect}" unless r.text_record.empty?
break unless r.flags.more_coming?
end
resolver.stop
puts "target: #{target}"
addrinfo = Socket.getaddrinfo target, nil, Socket::AF_INET
puts "Addresses for #{target}"
addrinfo.each do |addr|
puts addr.inspect
end
break
end
end
sleep 1
Enjoy!
Friday, February 25, 2011
Fix EventMachine::PeriodicTimer
EventMachine::PeriodicTimer doesn't give an accurate timing. For example, if I add a periodic timer with 1 second interval, in my Mac, it looks like this.
1. the test code.
2. output in my MacBook Pro.
As you can see, it drifted 100ms every time. Which is not very good when you want to do some job every 1 second. You might omit some seconds. So, with using the same method that I used for the Periodic ruby service, I made a change to PeriodicTimer. It looks like this.
So, here is the result (this is not that accurate like the simple ruby service, but reasonably useable.
That's it. :-)
1. the test code.
require 'eventmachine'
puts 'Start'
EM.run do
EM::add_periodic_timer 1.0 do
puts "time: #{Time.new.to_f.round(1)}"
end
end
2. output in my MacBook Pro.
time: 1298620726.9
time: 1298620728.0
time: 1298620729.1
time: 1298620730.1
time: 1298620731.2
time: 1298620732.3
time: 1298620733.4
time: 1298620734.5
time: 1298620735.5
time: 1298620736.6
time: 1298620737.7
time: 1298620738.8
time: 1298620739.9
time: 1298620741.0
time: 1298620742.0
time: 1298620743.1
time: 1298620744.2
time: 1298620745.3
time: 1298620746.4
time: 1298620747.4
time: 1298620748.5
time: 1298620749.6
As you can see, it drifted 100ms every time. Which is not very good when you want to do some job every 1 second. You might omit some seconds. So, with using the same method that I used for the Periodic ruby service, I made a change to PeriodicTimer. It looks like this.
# Override PeriodicTimer
module EventMachine
class PeriodicTimer
alias :old_initialize :initialize
def initialize interval, callback=nil, &block
# Added two additional instance variables to compensate difference.
@start = Time.now
@fixed_interval = interval
old_initialize interval, callback, &block
end
alias :old_schedule :schedule
def schedule
# print "Started at #{@start}..: "
compensation = (Time.now - @start) % @fixed_interval
@interval = @fixed_interval - compensation
# Schedule
old_schedule
end
end
end
So, here is the result (this is not that accurate like the simple ruby service, but reasonably useable.
time: 1298620683.4
time: 1298620684.4
time: 1298620685.4
time: 1298620686.4
time: 1298620687.4
time: 1298620688.4
time: 1298620689.4
time: 1298620690.4
time: 1298620691.3
time: 1298620692.3
time: 1298620693.4
time: 1298620694.4
time: 1298620695.4
time: 1298620696.4
time: 1298620697.4
time: 1298620698.4
time: 1298620699.4
That's it. :-)
Thursday, February 24, 2011
Ruby - Periodic Process
Ruby's sleep is not very accurate and Eventmachine's timer is also not very good. So, If you need to process one periodic job with some interval, this approach might be helpful. There is a compensation for sleep and you just need to define your process.
Here is the Service class.
And then, define your jobs in process method.
Try to run it..
And you will get a very accurate intervals
Next time, will try to fix Eventmachine timer..
Here is the Service class.
class Service
def initialize
@interval = 1.0
@start_time = Time.now
end
def start
# Update the start-time
@start_time = Time.now
# run loop
loop do
t_start = Time.now
# process the job
process
elapsed = Time.now - t_start
if elapsed > @interval
puts "Error: Job is bigger than Interval.. #{elapsed}"
end
# apply some compensation.
compensation = (Time.now - @start_time) % @interval
sleep (@interval - compensation)
end
end
def process
raise NotImplementedError
end
end
And then, define your jobs in process method.
class MyService < Service
def initialize
super
@interval = 2.0
end
def process
puts "time: #{Time.now.to_f.round(3)}"
# do the random job .. it takes upto 1.5 seconds.
sleep rand(150) * 0.01
end
end
Try to run it..
service = MyService.new
service.start
And you will get a very accurate intervals
time: 1298615010.271
time: 1298615011.271
time: 1298615012.271
time: 1298615013.271
time: 1298615014.271
time: 1298615015.271
time: 1298615016.271
time: 1298615017.271
time: 1298615018.271
time: 1298615019.271
time: 1298615020.271
time: 1298615021.271
time: 1298615022.271
time: 1298615023.271
time: 1298615024.271
time: 1298615025.271
time: 1298615026.271
time: 1298615027.271
time: 1298615028.271
time: 1298615029.271
time: 1298615030.271
time: 1298615031.271
time: 1298615032.271
time: 1298615033.271
time: 1298615034.271
time: 1298615035.271
time: 1298615036.271
time: 1298615037.271
time: 1298615038.271
time: 1298615039.271
time: 1298615040.271
time: 1298615041.271
time: 1298615042.271
Next time, will try to fix Eventmachine timer..
Sunday, February 13, 2011
NodeJS - HTTP Request
1. GET
2. POST
var http = require('http');
// GET.
var options = {
host: 'localhost',
port: 3000,
path: '/user/suwanny'
};
var req = http.get(options, function(res) {
console.log("Got response: " + res.statusCode);
res.on('data', function(chunk) {
console.log("Body: " + chunk);
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
2. POST
// POST.
var http = require('http');
var options = {
host: 'localhost',
port: 3000,
path: '/load/debug',
method: 'POST'
};
var req = http.request(options, function(res) {
console.log("Got response: " + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.on('data', function(chunk) {
console.log("Body: \n" + chunk);
});
});
req.end();
NodeJS - Socket.IO
1. ex_socketio.js
2. www/public/index.html
var express = require('express'),
server = express.createServer(),
io = require('socket.io');
server.configure(function(){
server.use(express.logger());
server.use(express.staticProvider(__dirname + '/www/public'));
});
server.listen(3000);
// socket.io
var socket = io.listen(server),
buffer = [];
socket.on('connection', function(client){
client.send({buffer: buffer});
client.broadcast({announcement: client.sessionId + ' connected'});
// new client is here!
client.on('message', function(message){
client.send({ message: "got your message: " + message});
client.broadcast({ message: client.sessionId + " sent message: " + message});
});
client.on('disconnect', function(){
client.broadcast({announcement: client.sessionId + ' disconnected'});
});
});
2. www/public/index.html
<html>
<head>
<title> Test </title>
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<h1> Hello NodeJS </h1>
<p> This is a static folder </p>
<p id="ann">empty now</p>
<p id="chat">empty now</p>
<script>
var socket = new io.Socket(null, {port: 3000});
socket.connect();
socket.on("message", function(obj) {
console.dir(obj);
if('buffer' in obj) {
document.getElementById('chat').innerHTML = '';
}
else {
if('announcement' in obj)
document.getElementById('ann').innerHTML = obj.announcement;
else
document.getElementById('chat').innerHTML = obj.message;
}
});
socket.send("this is the test message");
</script>
</body>
</html>
NodeJS - Express
This is an example which uses Express and Ejs with many configuration.
Here is the full guide http://expressjs.com/guide.html
1. Static files ..
2. View files (EJS)
layout.ejs
hello.js
3. nodejs application
Here is the full guide http://expressjs.com/guide.html
1. Static files ..
app.use(express.staticProvider(__dirname + '/www/public'));
2. View files (EJS)
app.set('views', __dirname + '/www/views');
app.set('view engine', 'ejs');
layout.ejs
<html>
<head><title>EJS Layout</title></head>
<body>
<%- body %>
</body>
</html>
hello.js
<h1>Hello</h1>
<h2><%= api %></h2>
3. nodejs application
// Production: NODE_ENV=production node ex_express.js
// Development: NODE_ENV=development node ex_express.js
var express = require('express'),
app = express.createServer();
app.configure(function(){
app.use(express.logger());
app.use(express.methodOverride());
app.use(express.bodyDecoder());
app.use(app.router);
app.use(express.staticProvider(__dirname + '/www/public'));
app.set('views', __dirname + '/www/views');
app.set('view engine', 'ejs');
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// Application.
app.get('/user/:id', function(req, res) {
res.render('hello.ejs', {locals: {"api": "user"}});
});
app.post('/load/:mode', function(req, res) {
// console.dir(req);
var body = "<h1>Load</h1>";
body += req.params.mode + "\n"
body += req.param("workers") + "\n"
res.send(body);
});
app.listen(3000);
console.log("Public Dir: " + __dirname + '/public');
console.log("Service Started at " + 3000);
NodeJS- Useful Modules
1. express (RESTful routing, http://expressjs.com/ )
http://expressjs.com/guide.html
High performance, high class web development for Node.js
Features
2. socket.io (Websocket)
http://soohwan.blogspot.com/2011/02/nodejs-socketio.html
3. couch_client (CouchDB)
4. node_redis (redis)
5. mDNS/Zeroconf/Bonjour (https://github.com/agnat/node_mdns)
Hmm unfortunately this is not useable in my Appliance, so I gave up to use this even though I need this feature.
Service Discovery
node_mdns – service discovery for node.js
node_mdns adds support for multicast DNS service discovery, also known as zeroconf or bonjour to node.js. It provides an object-oriented interface to announce and browse services on the local network.
Internally, it uses the mDNSResponder API which is available on all major platforms.
On Linux and other systems using the avahi daemon the avahi dns_sd compat library and its header files are required.
6. msgpack (gave up because it is hard to compile in my centos/mac)
A space-efficient object serialization library for NodeJS
http://expressjs.com/guide.html
High performance, high class web development for Node.js
var express = require('express');
var app = express.createServer();
app.get('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
Features
- Robust routing
- Redirection helpers
- Dynamic view helpers
- Application level view options
- Content negotiation
- Focus on high performance
- View rendering and partials support
- Environment based configuration
- Session based flash notifications
- Built on Connect
- Executable for generating applications quickly
- High test coverage
2. socket.io (Websocket)
http://soohwan.blogspot.com/2011/02/nodejs-socketio.html
3. couch_client (CouchDB)
4. node_redis (redis)
5. mDNS/Zeroconf/Bonjour (https://github.com/agnat/node_mdns)
Hmm unfortunately this is not useable in my Appliance, so I gave up to use this even though I need this feature.
npm install mdns
Service Discovery
node_mdns – service discovery for node.js
node_mdns adds support for multicast DNS service discovery, also known as zeroconf or bonjour to node.js. It provides an object-oriented interface to announce and browse services on the local network.
Internally, it uses the mDNSResponder API which is available on all major platforms.
On Linux and other systems using the avahi daemon the avahi dns_sd compat library and its header files are required.
var mdns = require('mdns');
// Browser.
var browser = mdns.createBrowser('http');
browser.on('serviceUp', function(info, flags) {
console.log("up");
console.dir(info);
});
browser.on('serviceDown', function(info, flags) {
console.log("down");
console.dir(info);
});
browser.on('serviceChanged', function(info, flags) {
console.log("changed");
console.dir(info);
});
browser.start();
// Advertisement.
// mdns.createAdvertisement('http', 4321).start();
6. msgpack (gave up because it is hard to compile in my centos/mac)
A space-efficient object serialization library for NodeJS
Saturday, February 12, 2011
NodeJS- Routing / Redis
This is an example for multiple listening ports.
2. Redis Example
3. Redis PubSub Example
var http = require('http');
var connect = require('connect');
http.createServer(function(request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World from 8124\n');
}).listen(8124);
var server = connect.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World from 3000');
}).listen(3000);
console.log('Server running at http://127.0.0.1:8124 & 3000');
2. Redis Example
var redis = require('redis'),
redis_client = redis.createClient();
redis_client.on('error', function(err) {
console.log("Error: " + err);
});
redis_client.set("Hello", "World", redis.print);
redis_client.hset("Hash", "field1", "value1", redis.print);
redis_client.hset(["Hash", "field2", "value2"], redis.print);
redis_client.hkeys("Hash", function(err, replies) {
console.log(replies.length + " replies:");
replies.forEach(function(reply, i) {
console.log(" " + i + ": " + reply);
});
// redis_client.quit();
});
var instruction = {
"id": "test1",
"musl": [ "1.mus", "2.mus", "3.mus"],
"hosts": {
"host_0": "a1",
"host_1": "a2"
}
};
/// --> this is not supported. (no nested object.)
redis_client.hmset("Inst1", instruction);
redis_client.hgetall("Inst1", function(err, obj) {
console.dir(obj);
});
var str_instruction = JSON.stringify(instruction);
console.log("str: " + str_instruction);
redis_client.set("instruction", str_instruction);
redis_client.get("instruction", function(err, value) {
console.log("get: " + value);
console.dir(JSON.parse(value));
});
// Publish/Subscribe
redis_client.on('message', function(channel, message) {
console.log("client1 channel " + channel + ": " + message);
});
redis_client.subscribe('testengine');
3. Redis PubSub Example
var redis = require("redis"),
client1 = redis.createClient(), client2 = redis.createClient(),
msg_count = 0;
client1.on("subscribe", function (channel, count) {
client2.publish("a nice channel", "I am sending a message.");
client2.publish("a nice channel", "I am sending a second message.");
client2.publish("a nice channel", "I am sending my last message.");
});
client1.on("message", function (channel, message) {
console.log("client1 channel " + channel + ": " + message);
msg_count += 1;
if (msg_count === 3) {
client1.unsubscribe();
client1.end();
client2.end();
}
});
client1.incr("did a thing");
client1.subscribe("a nice channel");
Thursday, February 10, 2011
A Simple Bash script to see the login information.
This is the script.
And, this is the output.
#!/bin/bash
for user in `ls -al /home | awk '{ print $9 }'`
do
echo $user
last -f /var/log/wtmp.1 -1 $user | head -1
last -1 $user | head -1
done
And, this is the output.
bxxxx
bxxxx pts/0 wireless1x............ Thu Jan 27 15:56 - 16:06 (00:09)
bxxxx pts/0 wireless1x-15-20 Tue Feb 1 11:44 - 12:19 (00:35)
Tuesday, February 8, 2011
CouchDB - Practice 01
With Curl
curl http://127.0.0.1:5984/
curl -X GET http://127.0.0.1:5984/_all_dbs
curl -X PUT http://127.0.0.1:5984/baseball
curl -X PUT http://127.0.0.1:5984/plankton
curl -X DELETE http://127.0.0.1:5984/plankton
Monday, February 7, 2011
Javascript MVC
This a practice to use Javascript MVC.
1. Download javascriptmvc from http://www.javascriptmvc.com/.
2. Move/Unzip and cd to your jmvc folder
3. Updates every sub libraries.
4. Generates your app
5. Make a Create-Read-Update-Delete (CRUD) scaffold.
6. Including Scripts
After generating the scaffolding files, you must steal them in your application file. Open cookbook/cookbook.js and modify the code to steal your recipe controller and model as follows:
cookbook/test/qunit/qunits.js
cookbook/test/funcunit/funcunit.js
7. That's it. open cookbook/cookbook.html
1. Download javascriptmvc from http://www.javascriptmvc.com/.
2. Move/Unzip and cd to your jmvc folder
3. Updates every sub libraries.
./js documentjs/update
./js funcunit/update
./js jquery/update
./js steal/update
4. Generates your app
./js jquery/generate/app cookbook
cookbook/cookbook.css
cookbook/cookbook.html
cookbook/cookbook.js
cookbook/controllers
cookbook/docs
cookbook/fixtures
cookbook/funcunit.html
cookbook/models
cookbook/qunit.html
cookbook/resources
cookbook/scripts
cookbook/scripts/build.html
cookbook/scripts/build.js
cookbook/scripts/clean.js
cookbook/scripts/docs.js
cookbook/test
cookbook/test/funcunit
cookbook/test/funcunit/cookbook_test.js
cookbook/test/funcunit/funcunit.js
cookbook/test/qunit
cookbook/test/qunit/cookbook_test.js
cookbook/test/qunit/qunit.js
cookbook/views
5. Make a Create-Read-Update-Delete (CRUD) scaffold.
$ ./js jquery/generate/scaffold Cookbook.Models.Recipe
cookbook/controllers
cookbook/controllers/recipe_controller.js
cookbook/fixtures
cookbook/fixtures/recipes.json.get
cookbook/models
cookbook/models/recipe.js
cookbook/test
cookbook/test/funcunit
cookbook/test/funcunit/recipe_controller_test.js
cookbook/test/qunit
cookbook/test/qunit/recipe_test.js
cookbook/views
cookbook/views/recipe
cookbook/views/recipe/edit.ejs
cookbook/views/recipe/init.ejs
cookbook/views/recipe/list.ejs
cookbook/views/recipe/show.ejs
Here's what each part does:
recipe_controller.js
- Cookbook.Controllers.Recipe, like all Controllers, respond to events such as click and manipulate the DOM.
edit.ejs,init.ejs,list.ejs,show.ejs
- Views are JavaScript templates for easily creating HTML.
recipe_controller_test.js
- Tests the CRUD functionality of the user interface.
recipe.js
- Cookbook.Models.Recipe model performs AJAX requests by manipulating services.
recipes.get
- Fixtures simulate AJAX responses. This fixture responds to GET '/recipes'.
recipe_test.js
- A unit test that tests Recipe model.
6. Including Scripts
After generating the scaffolding files, you must steal them in your application file. Open cookbook/cookbook.js and modify the code to steal your recipe controller and model as follows:
steal.plugins(
'jquery/controller',
'jquery/controller/subscribe',
'jquery/view/ejs',
'jquery/controller/view',
'jquery/model',
'jquery/dom/fixture',
'jquery/dom/form_params')
.css('cookbook')
.resources()
.models('recipe')
.controllers('recipe')
.views();
cookbook/test/qunit/qunits.js
steal
.plugins("funcunit/qunit", "cookbook")
.then("cookbook_test","recipe_test")
cookbook/test/funcunit/funcunit.js
steal
.plugins("funcunit")
.then("cookbook_test","recipe_controller_test")
7. That's it. open cookbook/cookbook.html
Thursday, February 3, 2011
CSS tutorial
Syntax
Two main parts:
- A selector
- Declarations
Selectors
1. ID selector
The id selector uses the id attribute of the HTML element, and is defined with a "#". The style rule below will be applied to the element with id="para1":
2. Class Selector
The class selector is used to specify a style for a group of elements. Unlike the id selector, the class selector is most often used on several elements. This allows you to set a particular style for any HTML elements with the same class. The class selector uses the HTML class attribute, and is defined with a "."
Two main parts:
- A selector
- Declarations
selector declarations
h1 {color: blue; font-size:12px; }
p {color:red;text-align:center;}
Selectors
1. ID selector
The id selector uses the id attribute of the HTML element, and is defined with a "#". The style rule below will be applied to the element with id="para1":
#para1
{
text-align:center;
color:red;
}
2. Class Selector
The class selector is used to specify a style for a group of elements. Unlike the id selector, the class selector is most often used on several elements. This allows you to set a particular style for any HTML elements with the same class. The class selector uses the HTML class attribute, and is defined with a "."
Wednesday, February 2, 2011
Studying jQuery
I'm reading Essential JavaScript & jQuery Design Patterns by Addy Osmani. He and many other gurus mentioned about "A Pattern Language". Should I read the book? It was published in 1977. Sounds old, but still referred. It means it's kind of Bible and people are interested "Pattern". I don't know how they are related. There is the main and most important book, "Design Patterns: Elements of Reusable Object-Oriented Software", which introduced and made "Design Patterns" popular to the world. It defines 23 core Object-Oriented design patterns.
Addy talked about Design Patterns in jQuery and Javascript. Here are Lists.
jQuery
- Lazy Initialization
- Composite
- Wrapper
- Facade
- Observer
- Iterator
- Strategy
- Proxy
- Builder
- Prototype
- Flyweight
Javascript
- Creational
- Constructor
- Singleton
- Module
- Revealing Module
- Prototype
- DRY
- Facade
- Factory
- Decorator
What is a pattern?
A: A pattern is a reusable solution that can be applied to commonly occurring problems in software design. There are three main benefits from Design Patterns.
1. Patterns are proven solutions.
2. Patterns can be easily re-used.
3. Patterns can be expressive.
However, Patterns are NOT an exact solution. It provides an idea and prototype. It can be building blocks and you can customize it for your project.
"Reusing patterns assists in preventing minor issues that can cause major problems in the application development process". - So, you can focus on your problem more. These days nobody starts from the scratch unless it is required.
"Patterns can provide generalized solutions which are documented in a fashion that doesn't require them to be tied to a specific problem."
"Certain patterns can actually decrease the overall file-size footprint of your code by avoiding repetition." - DRY (Don't Repeat Yourself)
A Good Pattern does these.
- Solves a particular problem.
- The solution to this problem cannot be obvious.
- The concept described must have been proven.
- It must describe a relationship.
Here is the rule of three for a valid pattern.
1. Fitness of purpose. - How?
2. Usefulness. - Why?
3. Applicability. - Wide?
----
The structure of a design pattern.
A design pattern must have a
- Pattern Name and a description
- Context outline
- Problem Statement
- Solution
- Design
- Implementation
- Illustrations.
- Examples
- Co-requisites
- Relations
- Known usage
- Discussions
Writing Design Patterns
- Bare in mind practicability
- Ensure that you draw upon best practices.
- Your design patterns should be transparent to the user.
- Remember that originality is not key in pattern design.
- Know the differences between patterns and design.
- Your pattern needs to have a strong set of examples.
Subscribe to:
Posts (Atom)