728x90
반응형

다양한 언어의 사용자들을 대상으로 웹 애플리케이션을 개발할 경우 국제화(Internationalization, i18n) 를 고려한 설계와 개발이 필요합니다.

 

국제화시 중요한 부분중에 하나는 사용하는 언어와 환경에 맞게 다양한 언어로 서비스를 제공하는 것입니다.

라라벨은 이를 위해 locale 환경 변수를 설정하고 번역된 메시지 파일을 만들어 주면 설정된 언어에 맞는 메시지 파일을 로딩하여 다개국어 애플리케이션을 제공할 수 있도록 지원하고 있습니다.

 

개발자는 다음과 같이 언어별 메시지 파일(기본 설정 - resources/lang/en/) 을 언어명(한글의 경우 ko) 폴더에 복사한 후에 해당 파일을 수정하면 되며 언어별 메시지 파일은 전 세계의 다양한 공헌자들에 의해 번역되어 있습니다.

/resources
 /lang
    /en
      messages.php 
    /ko 
      messages.php

 

예를 들어 프랑스어로도 서비스를 제공할 경우 검증 실패시 표시할 메시지 파일을 resources/lang/fr/messages.php 에 만들고 번역한 내용을 key/value 형식의 배열로 기술해 주면 되며 해당 메시지는 Lang::get($key) 메소드, 또는 이를 간략화된 trans($key) 메소드를 사용하여 로딩할 수 있습니다.

 

다음은 정해진 사이즈보다 큰 데이타가 입력되었을 경우 에러 메시지를 로딩하는 예제입니다.

public function getMaxFailedMessage()
{
    return Lang::get('messages.max.numeric', ['max'=>50'attribute' => 'username']);
}

실제 에러 메시지는 resources/lang/fr/messages.php 파일에 다음과 같이 배열로 기술되어 있으므로 언어별로 손쉽게 관리할 수 있으며 신규 언어가 필요할 경우 해당 메시지 파일만 번역하면 됩니다.

<?php
     
return [
    'max'                  => [
        'numeric' => 'The :attribute may not be greater than :max.',
    ],
];

메시지 파일중 런타임에 변경되어야 하는 부분이 있으므로 이는 위치 표시기(place-holders) 를 통해 지원하고 있으며 표시기는 :뒤에 속성 이름을 넣어주면 되며 위에서는 :max 와 :attribute 가 런타임에 동적으로 변경될 파라미터가 되며 최종 에러 메시지는 다음과 같이 변환됩니다.

The username may not be greater than 50.


출처 : https://www.lesstif.com/display/LIFE

728x90
반응형
728x90
반응형

초기의 PHP 는 사용자들의 요구에 맞게 다양한 C 라이브러리를 언어에 포함시켰으며 C 라이브러리 사용자를 고려하여 함수 이름 일치, 파라미터의 순서 일치등 최대한 호환성 확보에 노력을 기울였습니다.

 

이런 점은 기존 C 라이브러리 사용자들이 쉽게 PHP 에 적응할 수 있게 하는 장점이 있었지만 반대로 일관성이 없다는 단점을 만들게 되었습니다.

실제로 PHP 를 싫어하는 개발자들의 주요 이유중에 하나는 일관성 없는 문법과 라이브러리 사용이기도 합니다.

 

예로 html_entity_decode 함수와 쌍을 이루는 함수는 htmlentities 이며 문자를 소문자로 바꾸는 함수는 to 를 사용하여 strtolower이지만 헥사 문자열을 바이너리로 바꾸는 함수는 hex2bin 입니다.

파일이 있는지 확인하는 함수는 file_exist 이지만 파일을 여는 함수는 fopen 입니다.

 

이런 일관성 결여는 PHP 를 사용할 때 개발자를 혼란스럽게 하고 생산성이 떨어지며 자주 쓰지 않는 함수를 사용할 경우 매번 매뉴얼을 찾게 만들고 코딩 실수를 유발하는 원인이 되었습니다.

 

라라벨은 기존 PHP 함수에 대해 일관성있는 이름의 래퍼를 제공하고 기능을 확장 시켰습니다. 예로 파일 시스템을 다루는 함수는 Storage 클래스에 통합하고 이를 통해 파일이 로컬에 있든 아마존 클라우드에 있든 상관없이 일관성있게 사용할 수 있습니다.

<?php
// 아마존 S3 클라우드 디스크 객체 반환
$s3disk = Storage::disk('s3');
 
// 로컬 디스크 객체 반환
$localDisk = Storage::disk('local');
  
// 로컬 디스크에서 file.jpg 존재 여부 확인
$exists = $localDisk ->exists('file.jpg');
  
// 아마존 스토리지 파일의 마지막 변경 일시 확인
$time = $s3disk->lastModified('file1.jpg');

 

또 사용할 때마다 혼란스러운 PHP 의 배열에 대해서 헬퍼 함수를 제공하고 있으므로 편리하게 사용할 수 있습니다. 기존 PHP 에서 배열에 요소를 추가할 경우 array_push() 를 사용하지만 key/value 구조를 바로 넣을 수는 없습니다.

array_add1.php
1
2
3
4
5
6
7
<?php
$array = ['foo' => 'bar'];
  
// 배열에 key => value 형식으로 요소 추가
array_push($array, 'key''value');
  
var_dump($array);

위 소스를 실행하면 의도와는 달리 key와 value 라는 값이 각각 배열의 요소로 들어간 것을 확인할 수 있습니다.

php array_add1.php

 

.array(3) {
'foo' =>
string(3) "bar"
[0] =>
string(3) "key"
[1] =>
string(5) "value"
}

의도대로 동작하도록 코딩하려면 $array['key'] = 'value';  구문을 사용해야 합니다. 

이렇게 배열에 요소를 추가할 경우 array_push 를 사용하지만 배열에 key/value 요소를 추가할 경우 다른 문법을 사용해야 하는 건 코딩의 일관성을 떨어뜨리고 코딩 실수를 유발할수 있는 문제가 있습니다.

 

라라벨은 PHP 의 기본 함수중 일관성이 떨어지는 함수들에 대해 헬퍼(Helper) 함수를 제공하고 있습니다.

배열내 키가 존재하지 않을 경우 요소를 추가하는 array_add 헬퍼를 제공하므로 배열에 요소를 추가할 경우 다음과 같이 일관성 있게 코딩할 수 있습니다.

<?php
  
$array = ['foo' => 'bar'];
/**
array:2 [
  "foo" => "bar"
  "key" => "value"
]
*/
$array = array_add($array, 'key''value');

 

클래스와 메소드에 대해서는 언더바(_) 를 지양하고 카멜케이스(camelCase) 를 권장하고 있으므로 이에 익숙해지면 다른 개발자와 협업이 쉬워지며 가독성있고 간결한 코드를 작성할 수 있으며 이를 통해 생산성을 높이고 버그 발생 가능성을 줄일 수 있습니다.


출처 : https://www.lesstif.com/display/LIFE

728x90
반응형
728x90
반응형

설정보다 관례(CoC; Convention over Configuration)는 소프트웨어 개발자가 정해야 하는 수많은 결정들을 줄여주고 단순성을 확보하면서도 유연함을 잃지 않기 위한 설계 패러다임입니다.

 

프레임워크가 복잡해 지고 기능이 방대해짐에 따라 사용하기 위해서는 수많은 설정 파일과 세팅을 해야 하는 부담이 생겨났고 CoC는 이를 해결하기 위해 자주 사용하는 부분은 관례를 정하여 생략하고 이를 따르지 않을 경우에만 설정을 하도록 하고 있습니다.

 

많은 현대적인 프레임워크(Spring Framework, Ruby on Rails, Symphony 등)이 CoC 패러다임을 사용하고 있으며 라라벨도 CoC 패러다임에 입각하여 설계되었고 제공되는 기능들은 관례를 따르고 있습니다.

 

혹자는 CoC 패러다임을 적용하면 자유도가 떨어진다는 의견도 있지만 팀으로 일하게 되는 소프트웨어 개발 프로젝트의 특성상 표준화와 규격화가 정해지지 않는다면 공유와 협업이 힘들어 지고 잘못된 설정등으로 인한 버그 발생 소지가 크며 유지 보수가 어려워 지는 문제가 있습니다.

 

예를 들어 블로그 서비스를 개발하고 있고 게시 글의 카테고리를 저장하는 테이블인 article_categories 를 만들었을 경우 라라벨은  관련 모델 클래스는 ArticleCategory 라고 가정하고 동작하므로 개발자는 모델과 일치하는 테이블 이름이 다른 경우에만 설정을 하면 됩니다.

또 로그인을 처리하는 URL이 /auth/login(라라벨 5.1) 또는 /login(라라벨 5.2)이라고 가정하고 있으며 로그인에 성공할 경우 /home URL 로 리다이렉트 하도록 관례가 설정되어 있으므로 설정을 생략하고 별도의 URL 을 사용할 경우에만 설정을 해주면 됩니다.


CoC 는 이렇게 많은 설정 파일을 관리하고 세팅을 해주어야 하는 부담에서 벗어나 애플리케이션 개발에 집중할 수 있게 해주는 훌륭한 패러다임이지만 한 가지 문제가 있습니다.


관례를 모르면 어떻게 동작하는지 이해를 할 수가 없으므로 관례를 따르지 않을 경우(레거시 데이타베이스 등) 나 커스터마이징시 많은 어려움을 겪을 수 있으며 어디에서 관례를 찾아야 하는지 알기 힘들다는 점입니다.


출처 : https://www.lesstif.com/display/LIFE

728x90
반응형
728x90
반응형

의존성 주입(DI; Dependency injection)과 제어 역전(IoC; Inversion of Control)은 모듈간의 의존성을 줄이고 소스 수정없이 런타임에 더욱 유연한 소프트웨어를 만들수 있는 개발 패턴입니다.

 

의존성 주입은 객체 지향 언어에서 제공하는 인터페이스(Interface) 를 활용하여 구현됩니다.

 

사용자의 정보를 저장하고 읽어오는 UserRepository 클래스가 있고 이 안에는 저장소에서 사용자의 정보를 처리하는 $repository 라는 변수가 있습니다.

서비스 초기고 사용자가 적어서 사용자의 정보는 콤마로 구분된 CSV 파일에서 읽기로 하였습니다. 물론 향후 확장성을 위해 RepositoryInterface 라는 인터페이스를  만들고 CSVRepository 는  이를 구현한 클래스입니다.

1
2
3
4
5
6
7
8
9
10
 <?php
  
class UserRepository implements RepositoryInterface {
    private $repository;
  
    public function __construct() {
        $this->repository = new CSVRepository;
    }
}
  

이제 서비스 코드는 다음과 같이 인터페이스를 구현한 클래스의 인스턴스를 생성한 후 사용하도록 작성합니다.

// repository 생성 및 사용
$repos = new UserRepository();
$repos->store();

 

이제 서비스 사용자가  많아져서 사용자 정보를 MySQL DBMS 에서 처리하기로 하고 관련 로직을 구현하였습니다. 그리고 UserRepository 를 다음과 같이 수정합니다.

 <?php
  
class MySQLUserRepository implements RepositoryInterface {
    private $repository;
  
    public function __construct() {
        $this->repository = new MySQLRepository;
    }
}
// repository 생성 및 사용
$repos = new MySQLUserRepository();
$repos->store();

 

서비스는 더욱 사용자가 많아지고 성능 개선을 위해 저장소를 레디스(redis) key/value store 로 변경하기로 했습니다.

인터페이스를 잘 설계하고 이를 구현했다면 위와 같은 상황에서 RedisUserRepository 클래스를 구현하고 기존 서비스의 인스턴스 생성 소스를 수정하여 대처할 수 있습니다.

 <?php
  
class RedisUserRepository implements RepositoryInterface {
    private $repository;
  
    public function __construct() {
        $this->repository = new RedisRepository;
    }
}

 

하지만 외부에서 이 제품을 사용하겠다는 곳이 2개가 나타났는데 각각 DBMS 를 MS-SQL 과 PostgreSQL 을 사용한다고 합니다.

사용자 저장소를 인터페이스로 만들었지만 실제 서비스 코드에서는 인터페이스를 구현한 코드가 들어가야 하며 고객이 사용하는 DB 에 따라 제품을 나눌 경우 버전 관리가 매우 힘들어 지게 되며 새로운 DB가 추가될 경우 인스턴스를 생성하는 코드도 계속 수정되어야 합니다.

 <?php
  
class MSSQLUserRepository implements RepositoryInterface {
    private $repository;
  
    public function __construct() {
        $this->repository = new MSSQLRepository;
    }
}
// repository 생성 및 사용
$repos = new MSSQLUserRepository();
$repos->store();

 

의존성 주입과 제어의 역전 기술을 사용하면 인터페이스를 사용하는 소스의 수정없이 런타임에 의존성을 결정할 수 있습니다.

 <?php
  
class UserRepository implements RepositoryInterface {
    private $repository;
  
    public function __construct(RepositoryInterface $repository) {
        $this->repository = $repository;
    }
}

이제 의존성 제어 처리 로직에서 설정 파일이나 옵션에서 RepositoryInterface 를 구현한 인터페이스를 생성하여 UserRepository 에 주입해 주면 다른 저장소를 사용하는 곳이 나타나도 소스 수정을 하지 않고 설정으로 처리할 수 있습니다. 

$repos = App:make('UserRepository');
// $repos 사용

 

위와 같은 기법을 의존성 주입이라고 하며 외부에서 의존성이 주입되므로 이런 제어를 제어의 역전이라고 부릅니다. 

의존성 주입은 일반적인 서비스나 애플리케이션에서는 고려하지 않아도 되는 경우가 많지만 외부 환경에서 구동해야 하는 제품(솔루션, 프레임워크)은 도입을 고려해 봐야 하는  기능입니다.

 

의존성을 주입하는 방법은 위에서 설명한 생성자를 이용하는 방법과 세터(setter) 를 이용하는 방법이 있는데 라라벨은 전자를 사용하고 있습니다.

 

라라벨은 많은 부분을 런타임에 의존성을 주입하고 있으며 주입할 의존성 인터페이스는 타입 힌트를 통해 결정하고 있습니다.

또 의존성 인터페이스를 구체적으로 구현한 프로바이더는 보통 설정 파일에서 읽어 오므로 설정 파일의 내용만 변경하면 애플리케이션을 수정하지 않고 유연하게 패키지를 사용할 수 있습니다.

예로 config/session.php 내 세션 드라이버 설정을 다음처럼 한 줄만 바꾸면 캐시 데이타 저장소를 파일 시스템에서 DBMS 로 또는 redis 나 memcache 같은 key/value store 로 변경할 수 있습니다.

// 파일 세션 드라이버에서 레디스로 변경
//'driver' => env('SESSION_DRIVER', 'file')
'driver' => env('SESSION_DRIVER''redis')


출처 : https://www.lesstif.com/display/LIFE

728x90
반응형
728x90
반응형

라라벨 프레임워크는 컴포넌트(Component) 기반으로 기능을 확장할 수 있으므로 사용자는 손쉽게 원하는 기능이 없을 경우 이를 사용하여 기능을 확장할 수 있습니다.

또 기존 PHP 코드가 있다면 기존 코드를 크게 흔들지 않고 이를 라라벨 패키지로 재작성할 수 있습니다.

 

라라벨은 프레임워크의 코어와 패키지가 분리되어 있으므로 외부에서 만든 패키지를 탑재할 수 있으며 특히 컴포저(Composer) 를 지원하는 패키지라면 명령어 한 줄로 손쉽게 외부 패키지를 사용할 수 있습니다.

 

실제로 라라벨에서 제공하는 여러 패키지는 심포니(Symphony) 프레임워크에서 제공하는 기능을 확장하거나 또는 그대로 차용한 것도 많이 있습니다.

http://symfony.com/projects/laravel 에서 라라벨이 사용하는 심포니 프레임워크의 컴포넌트를 확인할 수 있습니다.

 

라라벨은 패키지 관리자로 컴포저(Composer)를 사용하므로 손쉽게 패키지간 의존성 관리를 할 수 있으며 http://packagist.org 같은 온라인 PHP 패키지 저장소에서 손쉽게 검색과 설치가 가능합니다.


출처 : https://www.lesstif.com/display/LIFE

728x90
반응형

+ Recent posts