목차
24.1. 목표 - 관례따르기
소프트웨어 공학적 습관
- Subversion이나 Git 같은 버전 관리 도구를 사용해 애플리케이션 소스코드를 관리
- 애플리케이션을 위한 자동화된 단위 테스트나 기능 테스트를 개발하고 실행
- 애플리케이션의 요구사항과 구현 전략을 기록하기 위해 명세서,문서,코드주석을 작성
24.2. 안티패턴 - SQL을 2등 시민으로 만들기
- 보통 DBA는 여러 개발팀을 지원하기 때문에 어느 팀에서도 완전한 팀원이 아니라는 인식
- SQL언어는 일반 프로그래밍 언어와 다르다
- SQL에는 관례를 적용하는것에 불편함을 느낌
- 데이터베이스 운영과 지식은 DBA 한사람에게 집중
24.3. 안티패턴 인식 방법
- "우리는 새로운 엔지니어링 프로세스를 채택했어. 즉 그것의 경량버전이야."
중요한 관례를 따르지 않겠다는 말을 완곡하게 표현한 것일 수도 있다. - "새로운 소스관리 시스템 교육에 DBA 직원들은 참가하지 앟ㄴ아도돼. 어쨌든 그들은 그걸 사용하지도 않거든."
기술팀원을 교육에서 배제하면 그들은 그 도구를 사용하지 않게 될 것 - "데이터베이스에서 테이블과 칼람의 사용률을 어떻게 추적할수있을까? 사용되지 않는거면 삭제해 버리려고"
어떤 테이블이나 칼럼의 목적을 당신이 모른다고 해도, 다른 누군가에게는 중요한 것이기 때문에 함부로 삭제하면 안 된다.
24.4. 안티패턴 사용이 합당한 경우
- 한번이상 사용할 모든 코드에대해 문서와 테스트작성, 소스관리도구나 기타좋은습관을 사용
- API함수를 어떻게 사용하는 것이었는지 확인하기 위한 테스트 코드나 사용자 질문에 답하기 위해 작성한 SQL 쿼리와 같은 임시적인코드도 작성
- 코드를 소스 관리 도구에 저장해야 하고 최소한 코드의 목적과 사용방법 정도의 간단한 기록은 남길 가치가 있음
24.5. 해법 - 초당적 품질 문화 확립
- QA수행하기위한 단계
1. 프로젝트 요구사항을 문서로 명확하게 명세한다.
2. 요구사항에 대한 솔루션을 설계하고 개발한다.
3. 솔루션이 요구사항에 맞는지 검토하고 테스트한다.
1) 증거1 - 문서화
1-1) ERD
1-2) 테이블,칼럼,뷰
- 어떤엔티티를 테이블로만든것인지, 각 테이블별로 얼마나 많은 행이 예상되는지,
테이블에 어떤쿼리가 들어올것으로 예상되는지, 테이블에 어떤 인덱스가 있는지 기술 - 칼럼에 어떤값이 의미를가지는지, 양을 저장하는 칼럼의경우에 측정단위가 무엇인지,
칼럼이 NULL을 허용하는지 하지않는지, 그이유는 무엇인지, 유일키 제약조건이있는지, 있다면 이유는무엇인지 등을 기술 - 뷰를 생성한 이유는 무엇인지, 어떤 AP 또는 사용자가 뷰를 이용할 것으로 예상되느지, 뷰가 테이블의 복잡한 관계를 추상화하는 의도인지
권한이 없는 사용자에게 권한이 필요한 테이블의 행이나 칼럼의 일부만 보여주기 위한 것인지, 업데이트가 가능한지 기술
1-3) 관계
- 암묵적 관계만 가지고 제약조건이 없는경우, 문서가 없으면, 관계가 있는지조차 알기 어렵다.
1-4) 트리거
- 어떤 비즈니스 규칙이 트리거로 구현되었는지 기술 (데이터검증,데이터변환, 데이터베이스 변경로깅 등)
1-5) 저장 프로시저
- 프로시저가 어떤 문제를 해결하는지, 프로시저가 데이터를 변경하는지, 입력 파라미터와 출력 파라미터의 데이터 타입과 의미는 무엇인지,
- 특정 형태의 쿼리를 대체해 성능 병목을 제거하려는 의도인지,
- 권한이 필요한 테이블에 권한이 없는 사용자가 접근할 수 있게 하는데 프로시저를 사용하는 것인지 기술
1-6) SQL보안
- AP에서 사용하기 위해 정의한 데이터베이스 계정은 무엇인지, 각 계정이 가지는 접근권한은 무엇인지, 어떤계정이 어떤 role을 가지고 있는지,
- 백업이나 보고와 같은 특정 작업에 사용하는 계정이 있는지,
- 시스템수준의 보안 규정(클라이언트가 SSL을 통해 DBMS서버에 접근하는지등)은 어떤것을 사용하고있는지,
- 무차별 대입공격과 같은 불법적 인증시도를 발견하고 차단하기 위해 어떤 방법을 취하고 있는지,
- SQL인젝션 취약점을 예방하기 위한 전반적 코드 검토를 실행했는지를 기술
1-7) 데이터베이스 기반 구조
- 사용하는 DBMS 제품 이름과 버전, 데이터베이스 서버 호스트네임, 여러대의 데이터베이스 서버를 사용하는지, 리플리케이션을 사용하는지, 클러스터를 사용하는지
- 프락시를 사용하는지 등을 기술
1-8) 객체 - 관계 매핑
- 프로젝트에서 ORM기반 코드 클래스 계층의 일부를 사용해 AP에서 몇몇 데이터베이스 처리 로직을 구현했을 수도있다.
- 어떤 비즈니스규칙이 이런방식으로 구현되었는지, 데이터 유효성 검증, 데이터 변환, 로깅, 캐싱 또는 프로파일리을 어떻게 하는지 기술
2) 증거의 흔적 - 소스코드 제어
- 소스관리시스템은 모든 변경 내역을 저장하기 때문에 점증적 백업이 가능하며, 어떤변경이든 되돌릴 수 있다.
- 데이터베이스 개발과 관련된 모든 파일을 소스 관리 시스템에 보관해야하는데, 다음과 같은 것이 포함된다.
2-1) 데이터 정의 스크립트
- 모든 데이터베이스 제품은 CREATE TABLE이나 다른 데이터베이스 객체를 정의하는 SQL문을 포함하는 스크립트를 실행하는 방법을 제공
2-2) 트리거와 프로시저
많은 프로젝트는 데이터베이스에 저장된 루틴으로 애플리케이션 코드를 보충한다. 이런 루틴이 없다면 AP는 동작하지 않을 것이므로 이런 루틴 역시 프로젝트 코드의 일부로 생각해야 한다.
2-3) 부트스트랩 데이터
초기 데이터라고도 함. 프로젝트 소스로부터 데이터베이스를 재생성할 필요가 있는 경우 도움이 됨.
2-4) ERD와 문서
데이터베이스 요구사항, 구현, 애플리케이션과의 통합을 기술. 프로젝트가 발전해가면 데이터베이스도 바뀌고 애플리케이션 코드도 바뀌므로 이들 파일도 최신 정보를 반영하도록 수정해야 한다. 문서가 현재의 설계를 기술하고 있는지 확인한다.
2-5) DBA 스크립트
불러오기/내보내기,동기화,리포팅,백업,데이터 검증,테스트 등 애플리케이션 밖에서 수행되는 데이터 처리 작업.
applicateion 코드와 데이터베이스 코드에 대해 동일한 저장소를 사용하는 것이 좋다.
*스키마 발전 도구
- 코드는 소스관린 시스템에 있지만 데이터베이스는 그렇지 않다. Ruby on Rails는 소스 관리 하에 데이터베이스 인스턴스 업그레이드를 관리하는 마이그레이션 기법을 보급했다.
예) 데이터베이스를 한 단계로 업그레이드 하는 스크립트를 데이터베이스 변경을 위한 Rails의 추상 클래스에 기반해 작성한다. 또한 업그레이드 함수의 변경을 반대로 하는 다운그레이드 함수도 작성한다.
class AddHoursToBugs < ActiveRecord::Migration
def self.up
add_column :bugs, :hours, :decimal
end
def self.down
remove_column :bugs, :hours
end
end
Rails 도구는 마이그레이션을 자동으로 실행하고 테이블을 생성해 현재 데이터베이스 인스턴에 적용할 리비전을 기록한다. Rails 2.1에서는 이 시스템을 좀더 유연하게 변경할 수 있게 되어, Rails의 후속 버전 또한 마이그레이션 작업과 동일하게 변경할 수 있다.
데이터베이스 스키마가 변경될 때마다 새로운 마이그레이션 스크립트를 작성한다.
데이터베이스 스키마를 한 단계씩 업그레이드하거나 다운그레이드하는 이런 마이그레이션 스크립트를 쌓아놓을 수 있다. 데이터베이스를 버전 5로 변경해야 하면, 마이그레이션 도구에 인수로 지정한다.
$ rake db:migrate VERSION=5
마이그레이션에 대해 더 많은 것을 배우고 싶다면 Agile Web Development with Rails, 3판 (RTH08) 또는 http://guides.rubyonrails.org/migrations.html 를 참조바란다.
PHP의 Doctrine, Python의 Django, Microsoft ASP.NET을 포함한 대부분의 다른 웹개발 프레임워크도 Rails의 마이그레이션과 비슷한 기능을 지원하는데, 프레임워크 자체에 포함되어 있거나 커뮤니티 프로젝트로 사용 가능하다.
마이그레이션은 소스코드 관리 하에 있는 프로젝트에서, 특정 리비전에 사용해야 하는 데이터베이스의 구조로 동기화하는 데 필요한 많은 지루한 작업을 자동화한다. 그러나 완벽한 것은 아니다. 마이그레이션은 몇몇 단순한 형태의 스키마 변경만 처리할 수 있"으며,ㅏ 기본적으로는 소스 코드 관리 시스템 위에서 리비전 시스템을 구현한 것이다.
3) 입증 책임:테스트
QA의 마지막 부분은 품질제어, 즉 애플리케이션이 기대대로 동작을 하는지를 검증하는것
PHPUnit 테스트 프레임워크를 사용한 단위 테스트 스크립트(데이터베이스를 검증하는 테스트)
<?php
require_once "PHPUnit/Framework/TestCase.php";
class DatabaseTest extends PHPUnit_Framework_TestCase
{
protected $pdo;
public function setUp()
{
$this->pdo = new PDO("mysql:dbname=bugs", "testuser", "xxxxxx");
}
public functon testTableFooExists()
{
$stmt = $this->pdo->query("SELECT COUNT(*) FROM Bugs");
$err = $this->pdo->errorInfo();
$this->assertType("object", $stmt, $err[2]);
$this->assertEquals("PDOStatement", get_class($stmt));
}
public function testTableFooColumnBugIdExists()
{
$stmt = $this->pdo->query("SELECT COUNT(bug_id) FROM Bugs");
$err = $this->pdo->errorInfo();
$this->assertType("object", $stmt, $err[2]);
$this->assertEquals("PDOStatement", get_class($stmt));
}
static public function main()
{
$suite = new PHPUnit_Framework_TestSuite(__CLASS__);
$result = PHPUnit_TextUI_TestRunner::run($suite);
}
}
DatabaseTest::main();
데이터베이스 검증하는 테스트 다음 체크리스트
3-1) 테이블,칼럼,뷰
- 테이블,뷰,컬럼이 실제로 존재하는지 ,삭제한컬럼이실제로 존재하지않는지 부정테스트(negative test)사용
3-2) 제약조건
- 제약조건때문에 발생할 Insert,UPDATE,DELETE문 실행, NOT NULL,유일키 제약조건,외래키 제약조건 위반 시도등
3-3) 트리거
3-4) 저장 프로시저
- 일반적인 단위테스트와 비슷, 프로시저의 모든면을 테스트
3-5) 부트스트랩 데이터
3-6) 쿼리
- 문법과 결과를 검증하기위해 테스트환경에서 실행
3-7) ORM(Object RealationShip Management) 클래스
- 트리거와 마찬가지로 ORM 클래스도 검증,변환,모니터링과 같은 로직을 포함. ORM기반의 추상화 코드 또한 다른애플리케이션 코드와 마찬가지로 테스트해야한다. 이런클래스들이 입력에 대해 기대대로 동작하는지, 유효하지않는값은 거부하는지 확인
4) 담당건수 - 여러 브랜치에서 작업하기
- 각 애플리케이션의 리비전마다 별도의 데이터베이스 인스턴스를 생성하는 것이 좋다. 또한 프로젝트 팀의 각 개발자가 별도의 데이터베이스 인스턴스를 가져 다른 팀원의 개발에 영향을 주지 않으면서 작업을 할 수 있어야한다.
- 파라미터를 조절해 데이터베이스 커넥션 설정을 바꿀수 있게해서 어떤 애플리케이션 리비전에서 작업하든 사용할 데이터베이스를 코드 수정 없이 지정할 수 있게 해야 한다.
- VMware Workstation,Xen,VitualBox와 같은 플랫폼 가상화 기술을 활용하면 모든 개발자가 서버기반구조를 적은 비용으로 복제할 수 있다.