티스토리 툴바


네이트 뉴스에서 보고 PC 사용에 도움주는 유틸리티 22선
입니다.
  • 그래픽 뷰어 유틸리티, Zviewer 5.1
  • 화면 캡쳐 유틸리티, 캡순이 v5.02
  • 일정 관리/메모 유틸리티, TransPlan
  • 문서 구조를 편리하게, SmartDraw
  • 마인드 맵 유틸리티, FreeMind
등이 쓸만하네요...
Posted by 여초
유능한 리더의 인재관리 철학을 간단하게(?) 3가지로 압축했다.
IT 인재를 관리하기 위한 세 가지 중요 지침
1) 인재를 모으는 지침
2) 인재를 유지하는 지침
3) 인재를 대하는 태도의 지침

소 잃고 외양간을 고치는 일이 없도록해야 겠다.
전에 봤던 블로그가 생각한다.
M$에서는 유능한 인재를 뽑지 못할 망정, 불적격자를 뽑지 말자.
라고 했단다.

우리 회사도 신입을 뽑았다가 2주일만에 편지(?)만 쓰고 도망을 갔다. ㅡ,.ㅡ;;;
내가 너무 닥달을 했나? 마음에 상처를 입히는 말을 했나?
도망가는 사람은 잡지 않는다. 하지만 회사를 나갈때는 사직서는 쓰고 나가길...

Posted by 여초
TAG 인재
JSP 2.0에서 바뀐내용을 손권남씨께서 번역하여 정리하여 주셨습니다.
감사합니다.

JSP 2.0: 뭐가 바뀌었나? - 1부
JSP 2.0: 뭐가 바뀌었나? - 2부
JSP 2.0: 뭐가 바뀌었나? - 3부
JSP 2.0: 뭐가 바뀌었나? - 4부
Posted by 여초
TAG JSP
위키북스에서 'Ajax 인 프랙티스'를 트랙백 이벤트를 하고 있습니다.
모두들 참여해 보세요. ^;

사용자 삽입 이미지

Ajax 인 프랙티스

'Ajax 인 프랙티스'는 저희 위키북스의 10번째 발간 도서입니다. 그래서 크게 이벤트 행사를 진행할까도 고민했지만, 살인적으로 치솟고 있는 국제 유가를 고려해서 평소와 같이 간단한 트랙백 이벤트 행사만 하기로 했습니다.(^^;)  

  'Ajax 인 프랙티스'는 Ajax 의 바이블로 알려진 'Ajax 인 액션'을 쓴 데이브 크레인이 Ajax와 웹 애플리케이션 개발 분야의 저명한 저자 5명과 함께 저술한 실용서 입니다.

  ‘Ajax 인 프랙티스’는 Ajax 솔루션을 개발하고자 할 때 직면하게 될 이슈들에 대한 많은 양의 재사용 가능한 코드를 제공하고 있습니다. 또 현재 Ajax에 관련된 최신 기술을 총 망라하고 있기 때문에 Ajax 기술 전반에 대한 커다란 그림을 그리실 경우에도 유용한 책이라고 생각됩니다.

앞에서도 말씀 드렸지만, 이 책은 저희 위키북스에서 낸 10번째 책입니다. 굳이 의미를 따진다면 이제 무사히 첫걸음을 내딛었다고 볼 수 있습니다. 앞으로 넘어야 할 산도 많겠지요. 자유롭게 걷기 위해 열심히 연습해야 하고, 그 다음엔 뛰어야 하고...앞으로도 독자 여러분의 아낌없는 조언과 사랑 부탁드립니다. 감사합니다.
Posted by 여초
위키북스에서 조엘 온 소프트웨어 시즌 2이벤트를 합니다.

사용자 삽입 이미지

시즌 2가 나왔네요...
홈페이지에서 구구절절한 이야기들을 읽고 감동받아 책도 샀는데...

똑똑하고 일잘하는 개발자를 모시고(?) 일을 하면 얼마나 좋을까요?
또한 제가 똑똑하고 백배 천배 일 잘하는 개발자가 될수 있도록 하루하루 노력이 필요하겠죠.

이벤트에 당첨이 되었으면...(좀 있다 머리가 벗겨질라! 걱정이네요.)
Posted by 여초
출처 : http://mongrel.rubyforge.org/docs/apache.html

By Charles Brian Quinn

The preferred setup (for now) is to put Mongrel behind an Apache 2.2.3 server running mod_proxy_balancer. Apache is a proven web server, runs half the Internet, and is a pain to configure. These instructions should get you started, but refer to the Apache folks for anything more complex or weird.

When you’re just starting out, don’t bother with doing anything but running just Mongrel. Mongrel is slower than Apache, but not so slow that small installations will notice it. The worst thing you can do is try to learn Apache install when you’re also trying to learn Ruby on Rails and Mongrel too. Start small, then when you need, build up to the big stuff.

A simple single mongrel configuration

Start up a single mongrel instance on port 8000:


$ mongrel_rails start -d -p 8000 \
-e production -P /full/path/to/log/mongrel-1.pid

Now, we’ll tell Apache to simply proxy all requests to the mongrel server running on port 8000. Simply add the following to your httpd.conf or in a vhost.conf file:


<VirtualHost *:80>
ServerName myapp.com
ServerAlias www.myapp.com

ProxyPass / http://www.myapp.com:8000/
ProxyPassReverse / http://www.myapp.com:8000
ProxyPreserveHost on
</VirtualHost>

That’s it, in a nutshell. Several things to note in this configuration:

1) This configuration forwards all traffic to mongrel. This means mongrel will serve images, javascript, files, and everything else. It’s quite fast at this, but Apache can do it better.

Here are some basic proxypass rules you can add to tell the ProxyPass not to forward on requests to certain documents/requests:


ProxyPass /images !
ProxyPass /stylesheets !
#continue with other static files that should be served by apache

Alias /images /path/to/public/images
Alias /stylesheets /path/to/public/stylesheets
#continue with aliases for static content

For a more detailed set of rules for forwarding on all dynamic content to mongrel, see the more detailed configuration below for more details.

2) In this configuration, it is entirely possible that two users (web requests) could hit your application at the exact same time, and one would have to wait literally milliseconds until the first request is finished before having a turn at the mongrel instance. Unless you’ve got some really long HTTP processes, the nature of the HTTP protocol is pretty good at waiting in line. Only you can determine (through metrics) how long and how many users will come at your application at the exact same time.

Sufficient to say, if you’re ready to start scaling with multiple mongrel instances, read on.

Using multiple mongrel instances with mod_proxy_balancer

First, let’s start up a few mongrel instances (*nix-style):


$ mongrel_rails start -d -p 8001 \
-e production -P log/mongrel-1.pid
$ mongrel_rails start -d -p 8002 \
-e production -P log/mongrel-2.pid
$ mongrel_rails start -d -p 8003 \
-e production -P log/mongrel-3.pid
$ mongrel_rails start -d -p 8004 \
-e production -P log/mongrel-4.pid

You can also use mongrel_cluster by Bradley Taylor for managing several mongrel instances with a configuration file (and sysv init scripts for *nix servers).

We’re going to be requiring the use of mod_proxy_balancer, a new feature in Apache 2.1/2.2 and above to proxy requests to our mongrel instances. This software based HTTP load balancer will distribute requests evenly (applying a weighting and selection algorithm) to our mongrel instance(s). It even comes with a swell load-balancing manager page for monitoring incoming requests. For more information, see: Apache’s mod_proxy_balancer Documentation.

Obtaining Apache 2(.1+)

I won’t go into too many details, as windows and the various linux distributions all have several methods for obtaining apache2, but you will need the use of the following modules:

  • mod_proxy, mod_proxy-html, and mod_proxy_balancer
  • mod_rewrite
  • mod_deflate
  • mod_headers
  • (optional) mod_cache and one of mod_memcache or mod_filecache
  • (optional) mod_ssl

If you’re compiling from source, this configuration should do the trick:


#./configure --enable-deflate --enable-proxy --enable-proxy-html \
--enable-proxy-balancer --enable-rewrite --enable-cache \
--enable-mem-cache --enable-ssl --enable-headers

Configuring Apache2

A good practice is the separation of apache configuration files. Recommended by several other good guides, we’ll be storing information for our application in several different files. Put these files somewhere that apache2 knows about. Apache is quite good about scanning for all .conf files in certain directories.

myapp.common

Apache lets you include common configuration items into another configuration so you can cut down on repetition. What we’re going to do is make a file that has all the common junk that every Mongrel application needs to work at all, then we’ll just include this in little .conf files for any application we deploy.

Notice that this file doesn’t end in .conf since it’s not a real configuration file, but you can name it however you wish.

Important Update: typo fixed in IE deflate rules


ServerName myapp.com
DocumentRoot /var/www/myapp.com/current/public

<Directory "/var/www/myapp.com/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>

RewriteEngine On

# Uncomment for rewrite debugging
#RewriteLog logs/myapp_rewrite_log
#RewriteLogLevel 9

# Check for maintenance file and redirect all requests
# ( this is for use with Capistrano's disable_web task )
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]

# Rewrite index to check for static
RewriteRule ^/$ /index.html [QSA]

# Rewrite to check for Rails cached page
RewriteRule ^([^.]+)$ $1.html [QSA]

# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

# Deflate
AddOutputFilterByType DEFLATE text/html text/plain text/css
# ... text/xml application/xml application/xhtml+xml text/javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

# Uncomment for deflate debugging
#DeflateFilterNote Input input_info
#DeflateFilterNote Output output_info
#DeflateFilterNote Ratio ratio_info
#LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
#CustomLog logs/myapp_deflate_log deflate

myapp.conf

We then take the above commmon file and include it in our configuration file for this application deployment.

If you’re using virtual hosting (a pretty good idea, even when you’re the only one on the server), your sample configuration can be this simple:


<VirtualHost *:80>
Include /etc/httpd/conf.d/myapp.common

ErrorLog logs/myapp_errors_log
CustomLog logs/myapp_log combined
</VirtualHost>

myapp.proxy_cluster.conf

This is the meat of our configuration, and goes hand in hand with our mongrel (or mongrel_cluster) configuration. This configuration tells the apache2 mod_proxy_balancer to proxy requests to 3 mongrel instances running on ports 8000, 8001, and 8002.


<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:8000
BalancerMember http://127.0.0.1:8001
BalancerMember http://127.0.0.1:8002
</Proxy>

If you had an seperate application server, you could balance to it easily by replacing the 127.0.0.1 with the ip or hostname of your application server, but be sure to make them listen on an external interface (rather than 127.0.0.1).

When you add an additional mongrel to your mongrel_cluster, you can simply add an additional BalancerMember to this file, restart apache (or reload) and you’re all set.

(optional) myapp.proxy_frontend.conf

This optional file will setup the balancer-manager—a simple front-end for viewing how your requests are being handled. This balancer in the configuration below will only work from the localhost, so no one else (or possibly you) can view it unless you alter the “Deny” and “Allow” lines.


Listen 8080
<VirtualHost *:8080>
<Location />
SetHandler balancer-manager
Deny from all
Allow from localhost
</Location>
</VirtualHost>

SSL Requirements

In order for mongrel to know that this request has a forwarded protocol of https, we’ll need to add a special header (hence the addition of mod_header, included in most apache2 builds).


Include /etc/httpd/conf.d/myapp.common

# This is required to convince Rails (via mod_proxy_balancer) that we're
# actually using HTTPS.
RequestHeader set X_FORWARDED_PROTO 'https'

You need this mostly so that redirects go back to https and so you can spot when people are coming through SSL or not.

Automation, Automation, Automation

There are several great tools that automate the setup of Apache for use with mongrel and mongrel_cluster. The RailsMachine gem can automate an entire setup of a Rails application. Also, Slingshot Hosting has a sample set of Capistrano recipes that automatically setup Apache2 and mongrel through the rake remote:setup task. Be sure to check out both for some ideas.

Running Multiple Rails Apps with Mongrel

The newest version of Mongrel supports multiple Rails applications through the use of the—prefix command. The Apache magic for proxying a single application is here assuming your prefix is app1:


ProxyPass /app1 http://127.0.0.1:3000/app1
ProxyPassReverse /app1 http://127.0.0.1:3000/app1

You need to have the proxy pass the new directory name.

Thanks to Joey Geiger and others of the mongrel list for these instructions.

Success Stories

Martins on the mongrel-list has submitted this simple apache configuration. It serves up static content with apache, and forwards dynamic content on to mongrel using ProxyPass. Thanks Martins:


<VirtualHost *>
ServerName myapp.tld
ServerAlias www.myapp.tld

DocumentRoot /var/www/sites/myapp/current/public

<Directory "/var/www/sites/myapp/current/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>

RewriteEngine On

# Check for maintenance file. Let apache load it if it exists
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteRule . /system/maintenance.html [L]

# Let apache serve static files
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteRule (.*) $1 [L]

# Don't do forward proxying
ProxyRequests Off

# Enable reverse proxying
<Proxy *>
Order deny,allow
Allow from all
</Proxy>

# Pass other requests to mongrel instance
ProxyPass / http://127.0.0.1:8200/
ProxyPassReverse / http://127.0.0.1:8200/

</VirtualHost>

Phillip Hallstrom has submitted this apache configuration, which includes support for having static directories handled by Apache, php support, and hiding svn directories.


<VirtualHost *:80>

ServerName myserver.com
DocumentRoot /path/to/my/app/public

<Directory "/path/to/my/app/public">
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>

<Proxy balancer://mongrel_cluster>
BalancerMember http://127.0.0.1:8805
</Proxy>

RewriteEngine On

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ $1/ [R]

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} \.php
RewriteRule ^(.*)$ $1 [QSA,L]

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.html -f
RewriteRule ^(.*)$ $1/index.html [QSA,L]

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.php -f
RewriteRule ^(.*)$ $1/index.php [QSA,L]

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d
RewriteRule ^(.*)[^/]$ $1/ [QSA,L]

RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml

BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html

php_value include_path /path/to/my/app/php:/usr/local/lib/php:.
php_value auto_prepend_file /path/to/my/app/php/auto_prepend.php

# this not only blocks access to .svn directories, but makes it appear
# as though they aren't even there, not just that they are forbidden
<DirectoryMatch "^/.*/\.svn/">
ErrorDocument 403 /404.html
Order allow,deny
Deny from all
Satisfy All
</DirectoryMatch>

</VirtualHost>

Jens Kraemer reports this differing proxy setup that uses the P option in Rewrite rules so as not to use the ProxyPass directive:


# Don't do forward proxying
ProxyRequests Off

# Enable reverse proxying
<Proxy *>
Order deny,allow
Allow from all
</Proxy>

RewriteEngine On

# Check for maintenance file. Let apache load it if it exists
RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteRule . /system/maintenance.html [L]

# Rewrite index to check for static
RewriteRule ^/$ /index.html [QSA]

# Let apache serve static files (send everything via mod_proxy that
# is *no* static file (!-f)
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule .* http://127.0.0.1:8200%{REQUEST_URI} [L,P,QSA]

the P option to the last rule replaces the ProxyPass and ProxyPassReverse directives.

SVN Security

If you use svn to issue checkouts instead of exports, you’ll need to hide those pesky .svn directories. This works:


# this not only blocks access to .svn directories, but makes it appear
# as though they aren't even there, not just that they are forbidden
<DirectoryMatch "^/.*/\.svn/">
ErrorDocument 403 /404.html
Order allow,deny
Deny from all
Satisfy All
</DirectoryMatch>

</VirtualHost>

Reading REMOTE_USER from mongrel through proxy

Jon Reads reports successfully reading the REMOTE_USER variable:

After many hours trying to solve the same problem I found this post: Forcing a proxied host to generate REMOTE_USER

and can confirm that the following works for me when put in the Proxy directive on Apache 2:


RewriteEngine On
RewriteCond %{LA-U:REMOTE_USER} (.+)
RewriteRule . - [E=RU:%1]
RequestHeader add X-Forwarded-User %{RU}e

References and Other Guides

[1] Time For A Grown-Up Server: Rails, Mongrel, Apache, Capistrano and You

[2] Bradley Taylor’s Fluxura and RailsMachine

[3] Slingshot Hosting Automated Capistrano Recipe

Thanks to many users on the mongrel list for making it easy for me to compile all these tips and tricks as they come across the list.


Posted by 여초

Trac

OpenSource 2007/07/02 10:32
Trac 홈페이지  : http://trac.edgewall.org/
 Trac is an enhanced wiki and issue tracking system for software development projects. Trac uses a minimalistic approach to web-based software project management. Our mission is to help developers write great software while staying out of the way. Trac should impose as little as possible on a team's established development process and policies.
    Trac 플러그인(1),  Trac 플러그인(2)  :  Track Hacks
    플러그인 설치 방법

Trac On Windows
All In On Packaging 형태로 제공되는 초간단 Trac 설치 버전

구성
  • Python 2.4.3 for win32
  • Apache 2.2 for win32
  • mod_python
  • clearsilver 0.9.14 for win32
  • Subversion 1.4.2
  • svn-python 1.4.2 for win32, Python 2.4
  • pysqlite 2.3.2 for win32, Python 2.4
  • Trac 0.10.3

다운로드

설치

Trac 한글 번역
Trac 0.10.4 버전까지 번역된 상태

Mylyn 연동 방법
Posted by 여초
출처 : ONJava.com
번역 : 한빛 네트워크 - 1부, 2부 (역자 : 백기선)

여러분의 애플리케이션을 처음 작성했을 때 데이터 모델은 거의 완벽했을 것입니다. 그 후로 계속 진화하고 있습니다. 데이터 모델이 엉망이 되고 역 정규화 되고 그 결과 회의를 할 때 그것들을 고쳐야 한다는 것에 열을 올려 설명해야 하는 수많은 시간을 소비하고 있습니다.

하지만 여러분은 불안해 합니다. 설득력 있는 언급에도 불구하고 “모든 데이터를 한번에 고치는 일”을 실천에 옮기기 꺼림칙합니다. 너무 위험합니다. 수많은 애플리케이션들이 해당 데이터베이스에 읽고 쓰기 작업을 하고 있습니다. 모든 것들을 한 번에 고칠 수 없습니다! 만약 한 번에 하나씩 데이터 모델을 수정할 수 있거나 한 번에 하나의 애플리케이션을 수정할 수 있다면 어떨까요.

정말 일반적인 경우에 다음과 같을 것입니다. 시간이 갈수록 IT 조직의 크기가 중소 기업이든, 대규모 기업이든 중앙 집중화된 데이터베이스에 저장되어 있는 중요한 데이터에 접근하는 별도의 애플리케이션을 만듭니다. 그리고 적당히 좋지 않게 설계된 데이터 모델은 성능과 확장성(scalability) 그리고 조직의 전반적인 효율성을 서서히 저하시키기 시작합니다.

이 기사에서는 현재 사용하고 있는 애플리케이션이나 프로세스에 영향을 주지 않고 결점이 있는 스키마와 데이터 모델을 수정하는 방법을 보여줄 것입니다. 하이버네이트(버전 3.0이상)에 있는 최신 기술(과 함께 데이터베이스 뷰, 스토어드 프로시저(stored procedure), 표준 디자인패턴)을 사용하면 애플리케이션 개발자와 데이터 아키텍처는 결함이 있는 데이터 모델을 한 번에 한 조각씩 수정할 수 있습니다.

수행 순서

앞으로 다음의 순서대로 할 것입니다.
  1. 개선된 데이터 모델 생각하기.: 현재 모델의 잘못된 점이 무엇인지 파악하고 어떻게 수정할지 결정합니다.
  2. 데이터베이스 뷰 만들기: 현재 (결함이 있는)모델에 비하여 이러한 뷰들은 여러분이 원하는 데이터 모델을 반영합니다.
  3. 스토어드 프로시저 또는 ‘instead of’ 트리거 만들기: 이것들이 기본 테이블에 대한 변경을 대체할 것입니다.
  4. POJO, 하이버네이트 맵핑, DAO를 개발: 새로운 데이터 모델을 표현하고 앞에서 작성한 뷰와 연결합니다.
  5. 테스트, 테스트, 테스트: 데이터 모델이 정확한지 증명합니다.
각각의 단계들을 좀 더 자세히 살펴봅시다. 그러나 그전에 간단한 예제를 살펴보겠습니다.

예제는 전반적으로 역정규화된 주문 시스템입니다. 기존의 데이터 설계자는 주문을 ORDER 테이블과 ORDER_ITEM 테이블로 나누지 않고 모든 주문 데이터를 CUST_ORDER라는 하나의 테이블에 넣기로 결정했습니다. 우리는 이 테이블을 둘로 나누고 싶습니다. 하지만 어떻게 할까요?

[그림 1]은 원래의 설계를 보여주고 있습니다.

figure
[그림 1] DMA 솔루션을 적용하기 전의 데이터 모델

오케이. 자 이제 고쳐봅시다.

개선된 데이터 모델 생각하기

우리는 이 테이블을 아주 간단하게 쪼갤 수 있다고 결정했습니다. [그림 2]에 보이는 것과 비슷하게 할 수 있습니다.

figure
[그림 2] 전반적으로 설계를 개선시키는 뷰를 포함한 데이터 모델

주문 데이터를 두 테이블로 나누면 데이터 중복을 피할 수 있고 보다 견고한 데이터 모델을 유지할 수 있습니다. 하지만 현재의 구조에서 어떻게 그러한 모델로 다다를 수 있을까요?

의사소통이 핵심입니다. 코딩과 테스트 할 것이 거의 없다 하더라도 가장 중요한 요소입니다. 모든 관련된 이해관계자들(stakeholder)이 여러분의 새로운 설계를 설명할 때 참석하도록 하세요. 이해관계자들이란 이 데이터에 접근하는 다른 애플리케이션을 구현하고 있는 개발자, 새로운 데이터 모델을 유지보수 할 데이터베이스 관리자 그리고 마지막으로 데이터 모델이 어떻게 변해야 하는지 각자의 생각을 가지고 있을만한 기술 관리자와 기술 비즈니스 분석가를 말합니다. 의사소통의 중요성은 아무리 강조해도 지나치지 않습니다.

데이터베이스 뷰 만들기

우리가 원하는 구조를 이루기 위해서 전반적으로 역정규화되어 있는 테이블을 사용하고 있는 기존의 스키마에서 데이터베이스 뷰를 정의합니다. 당연히 이 뷰는 정규화 되어 있는 상태로 데이터를 보여주겠죠. ORDER_V 뷰는 CUST_ORDER 테이블을 그룹화 하고 간추린 버전입니다. (구체적인 주문 아이템 정보를 제거하고 그것들을 order_id로 묶었습니다.) 다음과 같이 뷰를 정의했습니다.

CREATE VIEW dma_example.order_v
AS select
dma_example.cust_order.order_id AS order_id,
dma_example.cust_order.order_cust AS order_cust,
max(dma_example.cust_order.order_date) AS order_date
from dma_example.cust_order
group by dma_example.cust_order.order_id;

ORDER_ITEM_V 뷰는 오직 주문 아이템에 대한 상세 정보만을 담고 있으며 고객의 id와 (ORDER_V 뷰에서 포착할 수 있는)데이터는 제외했습니다. 다음과 같이 ORDER_ITEM_V 를 정의했습니다.

CREATE VIEW dma_example.order_item_v
AS select
dma_example.cust_order.order_id AS oi_order,
dma_example.cust_order.order_item AS oi_item,
dma_example.cust_order.order_item_price AS oi_price,
dma_example.cust_order.order_item_qty AS oi_qty
from dma_example.cust_order
where (dma_example.cust_order.order_item is not null);
지금까지 기본적으로 하나의 테이블을 둘로 나눴습니다.

스토어드 프로시저 또는 INSTEAD OF 트리거

이제 이 새로운 뷰들을 테이블처럼, 즉 핵심 컨텐츠들을 뒤에서 어떤 일이 벌어지든 신경 쓰지 않고 추가(Create), 수정(Update), 삭제(Delete)하고 싶습니다. 비록 몇몇 뷰들은 데이터베이스 설계 부서에 별도의 개입 없이 직접 수정을 할 수도 있겠지만 예제의 뷰는 약간 복잡합니다. 그리고 우리는 실제 데이터베이스 내부의 (CUST_ORDER) 테이블이 어떻게 영향을 받을지 확실히 알고 싶습니다. 최선의 방법은 뷰에 CUD 오퍼레이션을 수행하려고 할 때마다 실행할 코드를 데이터베이스에 정의하는 것입니다.

대부분의 데이터베이스(MS SQL Server, Sybase, Oracle, DB2)는 INSTEAD OF 트리거를(PostreSQL 은 비슷한 역할을 하는 “rules”를 사용한다.) 사용할 수 있습니다. 이것을 사용하여 뷰의 기본이 되는 테이블에 레코드를 추가, 수정, 삭제할 수 있습니다. 하지만 MySQL은 현재 INSTEAD OF 트리거를 지원하고 있지 않습니다. 대체제로 스토어드 프로시저를 만들 수 있으며 하이버네이트 맵핑 파일을 사용하여 이러한 스토어드 프로시저를 매번 CUD 오퍼레이션이 코드(와 하이버네이트에 의해 영속화되는 것)에 의해 트리거 될 때 마다 호출하도록 할 수 있습니다. 스토어드 프로시저 또는 Instead of 트리거의 코드는 매우 비슷합니다.

예제에서는 MySQL을 사용할 것이기 때문에 스토어드 프로시저를 사용하는 해결책을 선택했습니다.

코드

스토어드 프로시저로 역정규화 테이블에 추가, 수정, 삭제 작업을 할 때 반드시 역정규화의 모든 현상(반복되는 줄, 추가적인 필드, 불필요한 값 등)들을 고려해야 합니다. 이러한 스토어드 프로시저를 사용하면 위에서 정의한 잘 정규화된 뷰로 작성한 데이터 모델을 결함이 있고, 역정규화된 구조로 변환해줘야 합니다. 왜냐고요? 다른 애플리케이션들이 그런 구조의 데이터를 사용하고 있기 때문입니다. 게다가 우리가 작성한 뷰 정의도 기존 구조의 데이터에 의존하고 있습니다.

그럼 프로시저는 어떤 모습을 하고 있을까요? 다음에 주문 아이템을 추가하는 예제가 있습니다.
create procedure insert_order_item
(in itemprice FLOAT, in itemqty INT, in orderid INT, in itemid INT)
LANGUAGE SQL
BEGIN
DECLARE p_order_id INT;
DECLARE p_cust_id INT;
DECLARE max_order_id INT;
DECLARE p_itemprice FLOAT;

-- apply the current price to the line item
if itemprice is null then
select prod_price into p_itemprice from product
where prod_id=itemid;
else
set p_itemprice = itemprice;
end if;

-- get the customer id.
select order_cust into p_cust_id
from cust_order where order_id=orderid limit 1;

insert into cust_order
(order_id, order_cust, order_date,
order_item, order_item_price, order_item_qty)
values
(orderid, p_cust_id, now(), itemid, p_itemprice, itemqty);

END

ORDER_ITEM_V 뷰에서 어떤 데이터를 제외시켰든지 상관없이 모든 데이터를 CUST_ORDER 테이블에 추가해야 합니다. 이 프로시저가 CUST_ORDER 테이블에 추가하는 작업을 성공적으로 완료하면 영향을 받는 row의 숫자인 1을 반환할 것입니다. 각각을 테이블(실제로는 뷰이지만)에서 스토어드 프로시저들을 하나의 row로 취급하기 때문에 하이버네이트가 스토어드 프로시저의 결과로 1또는 0을 기대하고 있다는 것을 아는 것이 중요합니다. 실제 그런지 확인하기 위해 스토어드 프로시저를 가지고 작은 실험을 해볼 수 있습니다. 예를 들어, 하나의 주문 아이템을 업데이트 하기 위한 스토어드 프로시저가 CUST_ORDER 테이블의 여러 row(모든 주문 아이템에서 한 개의 row)에 영향을 끼칠 수 있을 것입니다. 만약 주어진 주문 ID를 가지고 있는 모든 row를 수정하려고 한다면 값이 바뀐 row의 수가 1보다 크게 됩니다. 이렇게 하면 하이버네이트에서 문제를 발생시키기 때문에 작은 테이블을 사용하고 CUST_ORDER 테이블을 수정한 다음에 갱신할 것입니다. 이렇게 하면 스토어드 프로시저가 영향을 받은 row의 숫자로 1을 반환합니다. (예상한 수정이 오직 하나의 row에만 변화를 주었기 때문에) 다음에 수정하는 스토어드 프로시저를 확인할 수 있습니다.

create procedure update_order
(in ordercust INT, in orderdate DATETIME, in orderid INT)
LANGUAGE SQL
BEGIN
update cust_order set order_cust=ordercust,
order_date=orderdate
where order_id=orderid;
if row_count() > 0 then
update help_table set i=i+1;
end if;
END
POJO, 하이버네이트 맵핑, DAO

새로운 뷰 기반 데이터 모델을 위한 POJO와 하이버네이트 맵핑을 작성하는 것은 매우 간단합니다. 하지만 몇 가지 주의해야 할 것들이 있습니다.

가상 외래키와 주키

비록 데이터베이스 뷰는 외래키와 주키를 가지고 있지 않지만 맵핑 파일에는 정의해야 합니다. 이렇게 함으로써 다른 개발자들이 새로운 데이터 모델을 마치 실제 물리적인 모델처럼 생각할 것입니다. 더 나아가, 이런 요소들을 맵핑하는 것은 실제 테이블에 기반한 마지막 솔루션으로 이동할 때 거의 연관성이 없어 보이는 변화를 신뢰할 수 있게 해줍니다.

추가, 수정, 삭제 재정의하기

스토어드 프로시저를 사용할 때는 반드시 스토어드 프로시저를 호출하도록 추가, 수정, 삭제를 재정의해야 합니다. (instead of 트리거를 사용할 때 이렇게 할 필요가 없습니다.) 맵핑 파일에 <sql-insert>, <sql-update>, <sql-delete> 엘리먼트를 사용하여 설정할 수 있습니다. 이 엘리먼트들은 데이터베이스에 직접 추가, 수정, 삭제를 하는 대신 하이버네이트가 호출할 프로시저를 알려줍니다. 다음에 ORDER_V 맵핑 정보가 나와있습니다.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
<class name="org.onjava.shared.vo.Order" table="order_v"
catalog="dma_example">

<id name="orderId" type="int" column="order_id" />
<property name="orderCust" type="int" column="order_cust" />
<property name="orderDate" type="timestamp" column="order_date"
length="19"/>
<set name="items" inverse="true" cascade="all-delete-orphan"
lazy="true">
<key column="oi_order"/>
<one-to-many class="org.onjava.shared.vo.OrderItem" />
</set>

<sql-insert callable="true">
{call insert_order(?, ?, ?)}
</sql-insert>
<sql-update callable="true">
{call update_order(?, ?, ?)}
</sql-update>
<sql-delete callable="true">{call delete_order(?)}</sql-delete>
</class>
</hibernate-mapping>
이때 파리미터의 순서가 중요합니다. 하이버네이트 매뉴얼 중 custom SQL reference 부분을 참조하여 스토어드 프로시저의 파라미터 순서를 정하시기 바랍니다.

데이터 접근 객체

제대로 된 맵핑이 자리를 잡으면, 뷰 기반 데이터 모델의 데이터 접근 객체는 테이블 기반 모델과 동일합니다. 하이버네이트가 스토어드 프로시저의 실행을 책임지고 뷰들을 테이블처럼 다루게 됩니다. 본 기사의 예제인 DMA 솔루션으로 완성된 ORDER_V와 ORDER_ITEM_V 뷰를 위한 데이터 접근 클래스를 참조하세요.

테스트, 테스트, 테스트

DMA 솔루션을 생성할 때 가장 중요한 것 중 하나가 전역적인(Extensive) 테스트 입니다. 오직 테스트를 통해서만 뷰 기반의 (논리적) 데이터 모델이 정확히 동작하는지 확인할 수 있습니다. 새로운 데이터 모델의 모든 측면이 테스트를 통해 확인되어야 합니다. 그리고 당연히 잘 작동하는 경우와 오동작하는 경우를 테스트 해봐야 할 것입니다.

DBUnit은 자동화 테스트를 훌륭히 도와줍니다. 비록 여기서는 DBUnit을 어떻게 사용할지 자세히 다루지는 못하지만(Andrew Glover가 작성한 이와 관련된 좋은 OnJava 기사가 있습니다.) 몇 가지 중요한 것들을 살펴보겠습니다.
  • 데이터 다양성(Data diversity) 테스트 데이터가 확실히 (외래키 관계와 빈(null) 값과 같은)모든 종류의 데이터 시나리오를 반영하고 있는지 확인합니다.
  • 데이터셋 규모(Dataset size) 물론 여러분의 모든 테스트를 지원하기 위한 상당히 많은 데이터를 유지하는 것은 중요하지만 DBUnit을 사용하여 모든 테스트 메소드 마다 데이터를 지우고 다시 읽어 들일 수 있다는 것을 기억하시기 바랍니다. 상당히 많은 데이터는 테스트를 느리게 만듭니다.
테스트 할수록 DAO와 값 객체(Value Object)를 단련 시키는 것으로 생각할 수 있습니다. 여기 우리가 추천하는 몇 종류의 테스트가 있습니다. 구현한 것을 자세히 살펴보시고 이 기사에 있는 예제 코드를 보시기 바랍니다.
  • Find All DAO가 예상한 만큼의 row의 개수를 반환하는지 확인
  • Find one 가상 주키를 사용하여 레코드를 가져오고 가져온 레코드의 모든 값(컬럼)들이 예상한 값들과 같은지 확인
  • Insert 레코드 하나를 추가하고 추가 되었는지 확인
  • Insert multiple records 한 번에 하나 이상의 레코드를 추가하는 것이 제대로 동작하는지 확인
  • Insert duplicates 가상 주키의 제약 사항을 어기는 것을 시도
  • Delete 레코드를 삭제해보고 진짜로 제거 되었는지 확인
  • Delete multiples 여러분이 설계한 DAO가 이 기능을 지원할 때 해보세요.
  • Update 수정을 하고 DB에 수정된 내용이 영속화 되었는지 확인
  • Violate constraints 모든 가능한 가상 제약들을 테스트했는지 확인
  • Optimistic locking 낙관적인 롹킹 예외(optimistic locking)를 발생할 수 있는 몇 가지 방법들이 있습니다. 낙관적인 롹킹 예외가 제대로 동작하는지 확인하려면 다음의 네 가지 조건을 확인해봐야 합니다.
    • 이미 삭제한 레코드를 삭제하려고 할 때
    • 최근 팻치(fetch)로 수정된 레코드를 삭제하려고 할 때(이 것은 버전 컬럼을 사용할 때 가능합니다.)
    • 삭제된 레코드를 수정하려고 할 때
    • 최근 팻치(fetch)로 삭제된 레코드를 수정하려고 할 때(이 것은 버전 컬럼을 사용할 때 가능합니다.)
위의 모든 경우를 테스트 했다면 새로운 데이터 모델이 폭탄을 가지고 있지 않다는 자신감을 가질 수 있습니다.

평화로운 공존 정책

이제 애플리케이션이 정상적인 데이터 모델을 사용하도록 수정했습니다. 다른 애플리케이션들도 같은 데이터를 약간 다른 관점에서 접근할 수 있다는 것을 고려해야 합니다. 그렇다고 걱정할 필요는 없지만 그냥 그렇다는 것을 기억하고 있기만 하면 됩니다. [그림 3]은 새롭게 진보된 애플리케이션이 어떻게 기존의 애플리케이션과 평화롭게 공존하는지 보여줍니다.

figure
[그림 3] 기존 애플리케이션과 DMA 솔루션이 평화롭게 공존하고 있으며 같은 서로 다른 모델을 통해서 같은 데이터 셋을 사용하고 있습니다.

이제는 무엇을 해야 할까요? 기반이 되는 데이터 모델 이전하기

데이터모델을 수정하기 위해 멋진 해결책을 구현했습니다. 수 개월이 지나고 개발자들이 그들의 애플리케이션을 수정해 감으로써 점점 새로운 뷰 기반의 데이터 모델을 사용하기 시작했습니다. 하지만 그 기반이 되고 있던 역정규화 상태(또는 잘못 설계된)는 여전히 존재하고 있으며 그것을 제거하고 싶습니다. 하지만 어떻게 할까요? 여러분이 생각하는 것보다 실제는 더 간단합니 다. 다음에 단계별 가이드가 있습니다.

  1. Develop tables: These will look much like your views, but will have real foreign keys and indexes. Make sure to maintain the same column names as the views themselves.
  2. 테이블 만들기 : 뷰와 상당히 비슷하게 만들어지겠지만 진짜 외래키와 인덱스를 가지고 있습니다. 뷰와 같은 컬럼 이름을 사용하는지 확인하기 바랍니다.
  3. Load tables: You will load the tables with data from your already existing views. Select from view into table. It's really that simple.
  4. 테이블 로딩하기 : 기존의 뷰에 이미 존재하는 데이터를 가지고 테이블을 로딩합니다. 뷰에서 테이블로 선택을 변경 합니다. 실제로 간단합니다.
  5. 맵핑 파일 수정하기 : 하이버네이트 맵핑을 변경하여 뷰 대신에 테이블을 사용하고, 만약 스토어드 프로시저를 사용한다면 <sql-insert>, <sql-update>와 <sql-delete> 엘리먼트르르 제거합니다.(더 이상 필요 없기 때문이죠.)
  6. 테스트, 테스트, 테스트 : 기존의 테스트들은 절대로 수정할 필요가 없습니다. 그것들을 계속하여 다시 실행하면서 검증하면 됩니다.
자 보세요! 여기까지 제대로 했다면 한 줄의 자바 코드도 필요 없이 수정 했으며 애플리케이션은 기존과 동일하게 동작합니다. 바로 이 부분이 이런 해결책이 아름답다는 것을 분명히 해줍니다. 데이터 모델을 하이버네이트로 추상화하고 데이터베이스의 프로시저를 사용하여 작은 노력으로 엄청난 변화를 줄 수 있습니다. 물론 이것이 모든 것을 다시 테스트하지 않아도 된다는 것을 의미하지 않습니다. 희소식은 여러분의 테스트가 여전히 유효하다는 것입니다. (만약 XML 데이터 셋을 사용하고 있다면 뷰 이름을 테이블 이름으로 변경해야 합니다.)

결론

최신의 그리고 훌륭한 하이버네이트의 기능과 자바 테스트 방법론 그리고 데이터베이스 자원을 잘 활용하면 점진적인 변화가 가능하다는 것을 보여드렸습니다. 데이터 모델의 문제를 이러한 방법으로 해결할 때 마법 같은 것은 이 해결책이 상호 배타적이라는 것입니다. 이 말은 여러분이 문제를 해결한 것을 (자신의 애플리케이션에서) 사용하더라도 같은 데이터를 사용하는 다른 애플리케이션들이 기존의 테이블을 사용하다가 여러분이 만든 개선된 것으로 옮기기 전까지 지속적으로 제대로 동작할 것 입니다. 친화적인 데이터 모델 마이그레이션 방법입니다.

마지막 요약으로 여러분의 솔루션을 구현할 때 다음의 몇 가지 사항들을 유념하시기 바랍니다.
  • 제로 임팩트(Zero impact) DMA 솔루션은 기존의 애플리케이션이나 프로세스에 영향을 주면 안됩니다. 이 말은 새로운 (가상) 데이터 모델이 변경 되면 실제 (결함이 있는 데이터 모델의) 데이터도 변경되어야 한다는 것입니다.
  • 기능성 유지 새로운 데이터 모델이 특정 컬럼의 중요성을 제거 하더라도 지속적으로 예전의 행위를 유지할 수 있어야 하는 것이 중요합니다. 계산되는 필드가 이에 가장 적합한 예입니다. 만약에 기존 애플리케이션이 추가하기 전에 계산을 하지만 새로운 모델은 심지어 해당 필드를 가지고 있지 않다면 DMA 솔루션은 기존의 행위를 보장해야 하며 필드를 계산해야 합니다. (그리고 추가도 해야겠죠.)
  • 완벽한 자신감을 위한 테스트 DMA 솔루션은 충분히 테스트해야 새로운 스키마가 기존의 데이터베이스 스키마만큼 튼튼하다는 자신감을 가질 수 있습니다. DMA 패턴은 단순하게 테이블과 컬럼을 맵핑하는 것이 아니기 때문에 버그가 생기기 쉽습니다. 시도를 한 다음 테스트를 토해서 솔루션이 제대로 됐으며 완벽한 ACID 원칙들을 보장하는지 확인할 수 있습니다.
Resources * Gilad Buzi 는 10년 넘게 데이터 주도 애플리케이션 개발과 관련된 일을 하고 있습니다. 그는 현재 Code Works, Inc에서 선임 개발자(Principal Software Engineer)로 활동하고 있습니다.
* Kelley Glenn은 10년 넘게 소프트웨어 개발 산업에 종사하고 있으며 전화 요금과 엔터프라이즈 애플리케이션 통합의 경력을 가지고 있습니다.
* Jonathan Novich는 Code Works, Inc의 공동 설립자이자 파트너며 소프트웨어 컨설팅과 개발에 10년 넘게 종사하고 있습니다.
Posted by 여초
출처 : 웹초보

“태훈”이라는 님이 불여우의 확장기능이나 자잘한 설정등을 백업하는 방법에 대해 이메일로 문의해주셨습니다.

여러가지 방법이 있겠지만.. 가장 간단한 방법은 MozBackup이라는 유틸리티를 사용하는 것입니다. MozBackup은 파이어폭스와 썬더같은 모든 모질라 재단의 소프트웨어들을 백업할수 있으며, 파이어폭스에서는 북마크 / 사용기록 / 패스워드 / 쿠키 / 저장된 폼 / 다운로드된 파일목록 / 인증서를 백업할수 있습니다.

다만 확장기능의 경우는 이미 MozBackup에서 설정된 몇가지 유명한 확장기능만 백업할수 있기때문에 조금 다양한 종류의 확장기능을 사용한다면 FEBE라는 확장기능을 백업해주는 확장기능을 사용하시면 깔끔하게 백업할수 있습니다.

MozBackup 다운로드

FEBE 다운로드

 

MozBackup은 이미 한글화가 된 프로그램이기 때문에 한글 언어 파일만 다운로드해서 설치 폴더에 덮어씌어주면 별다른 어려움없이 작업 할 수 있습니다. (한글화 작업해 주신 분들 감사합니다.. ^^*)

프로파일을 선택한후 백업할 요소들을 선택한 다음 백업하면 지정된 폴더에 .PCV라는 파일로 백업이 됩니다. 나중에 파이어폭스를 다시 깔면 MozBackup을 구동시켜 이 파일로 복원시키면 되겠습니다.

 

FEBE의 경우는 확장기능으로 설치되기 때문에 도구 메뉴의 FEBE에서 Perform Backup을 눌러주시면됩니다. 마찬가지로 복구는 Restore를 선택하고 복구할 확장기능이나 테마를 선택하면됩니다.

Options에서 백업할 폴더를 지정할수 있으며 확장기능 말고도 북마크 / 쿠키 같은 여러가지 다른 요소들도 백업하도록 설정할수 있습니다만 이미 여타 요소들은 MozBackup으로 백업하는게 편하기 때문에 FEBE는 단순히 확장기능만 백업하는 용도로 사용하는게 더 편한것 같습니다.

백업을 마치면 다음과 같은 깔끔한 리포트를 볼 수 있습니다.


위의 방법은 유틸리티를 사용하는 방법이지만,
가장 간단한 방법은 프로필 폴더를 통째로 백업하는 방법입니다.
C:\Documents and Settings\${USER_DIR}\Application Data\Mozilla\Firefox
폴더를 압축 백업합니다.
폴더에는 확장 기능 뿐만 아니라 북마크등 그동안 저장된 모든 설정이 백업됩니다.

Posted by 여초
사용자 삽입 이미지

Modern Life

나(?)에게 정말 딱 맞는 하루 일과를 4칸 만화로 표현하고 있네요...
점점 현대 생활이 발전(?)해 감에 따라 점점 많은 분들의 일과가 될거 같습니다. ^^;
Posted by 여초