객체 지향 프로그래밍에 익숙한 개발자라면 하나의 파일에 하나의 클래스를 작성하는 방식에 익숙할 것이다. 다만 php는 다른 언어와 같이 라이브러리를 일괄적으로 불러오는 방법이 없어 위와 같은 접근 방법으로는 require 또는 include를 이용해 수많은 단일 파일을 불러들여야만 했었다.

PHP5에서는 클래스 또는 인터페이스 등을 호출했을 때 해당 파일을 자동으로 불러올 수 있도록 여러 함수를 제공한다. 먼저 __autoload 함수를 이용한 예제다.

<?php
function __autoload($className){
  include $className . '.php';
}

$foo = new Foo();
$bar = new Bar();
?>

위와 같이 함수를 선언하면 new Foo()와 같이 클래스를 사용하는 순간 해당 클래스명으로 __autoload 함수가 실행, Foo.php 파일을 include한다.

다만 __autoload 함수는 spl_autoload_register 함수를 통해 대체될 수 있기 때문에 권장되지 않는다. spl_autoload_register는 다음과 같이 사용한다.

<?php
function my_autoloader($className){
  include 'classes/' . $className . '.class.php';
}

spl_autoload_register('my_autoloader');
?>

PSR-0 Autoloading Standard

위 함수를 통해 모듈화가 가능하도록 PHP Framework Interop Group(PHP-FIG)에서 PSR-0 Autoloading Standard가 제안되었다. 해당 제안은 다음의 규약을 포함하고 있다.

  • 네임스페이스와 클래스명으로의 자격을 갖추기 위해서는 다음의 구조를 따라야 한다. \<Vendor Name>\(<Namespace>\)*<Class Name>
  • 각 네임스페이스는 최상위 네임스페이스를 가져야 한다. (“Vendor Name”)
  • 각 네임스페이스는 필요에 따라 서브 네임스페이스를 가질 수 있다.
  • 각 네임스페이스 구분자는 파일 시스템에서 해당 파일을 불러오기 위한 디렉토리 구분자로 사용된다.
  • 클래스명에 들어있는 _ 글자도 디렉토리 구분자로 사용된다. 네임스페이스에서의 _는 특별한 의미가 없다.(PEAR 구현을 포함)
  • 완전한 네임스페이스와 클래스는 파일 시스템에서 불러올 때 .php를 접미어로 붙여 불러온다.
  • 알파벳으로 구성된 벤더명, 네임스페이스, 클래스명은 대소문자를 구분한다.

위 규약에 따른 예제는 PSR-0 문서에서 제공되고 있으며 SplClassLoader 구현도 해당 문서에서 확인할 수 있다.

다음은 문서에서 제공되는 autoload 함수 예제다.

<?php
function autoload($className) {
  $className = ltrim($className, '\\');
  $fileName = '';
  $namespace = '';
  if($lastNsPos = strpos($className, '\\')) {
    $namespace = substr($className, 0, $lastNsPos);
    $className = substr($className, $lastNsPos + 1);
    $fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
  }
  $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
  require $fileName;
  }
}
?>

Composer 활용하기

Composer는 PSR-4 Autoloader 제안과 함께 위에서 살펴본 PSR-0를 준수하고 있어서 간단한 설정으로 PSR-0 방식을 사용할 수 있다. composer.json에 autoload 경로를 등록하면 composer의 ClassLoader와 맵핑되어 자동으로 불러온다.

{
  ...
  "autoload": {
    "psr-0": {"": "<path>/"}
  },
  ...
}

위 내용을 추가한 후 composer update 등을 통해 갱신하면 vendor/composer/autoload_namespaces.php 파일 안에 composer.json에서 작성한 경로가 추가된 것을 확인할 수 있다.

더 읽을 거리

터미널에서 rename을 이용하면 정규표현식으로 한번에 파일 이름을 변경할 수 있다. mac에 기본적으로 없는 것 같으니 homebrew를 이용해서 rename을 설치한다.

brew install rename

rename 정규식 파일조건으로 변경할 수 있다.

rename s/en\-US/en\-AU/ *.html

변경 전에 어떤 식으로 변경이 될지 -n 플래그를 사용해 확인할 수 있다.

rename -n s/en\-US/en\-AU/ *.html

OWIN은 Open Web Interface for .NET의 약어로 요즘 MS 진영에서 핫한(?) 오픈소스 프로젝트다. 다음은 OWIN 공식 사이트에 나와 있는 프로젝트의 목표.

The goal of the OWIN interface is to decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

MS에서 제공하는 ASP.NET MVC framework는 System.Web에, 특히 HttpContext에 깊은 의존성이 있어서 IIS 이외에는 구동이 불가능하다. 하지만 OWIN 구현을 통해 웹서버와 어플리케이션의 의존성이 분리1되어 IIS 이외의 웹서버에서도 C#으로 작성된 웹 어플리케이션을 구동할 수 있게 되었다.2 OWIN은 인스턴스로 처리하기 간편한 구조라 횡적으로 확장이 쉬운데다 서버의 유연성까지 보장하고 있다. OWIN을 이용해 개발한다면 ASP.NET MVC을 기반으로 작업할 수 없지만3 Nancy나 Simple.Web 등 다양한 프레임워크/라이브러리를 활용할 수 있다.

OWIN의 구조

OWIN 명세에서는 각각 서버, 웹프레임워크, 웹 어플리케이션, 미들웨어, 호스트로 정의했다. 발번역(…)하면 다음과 같다.

  • 서버: HTTP 서버로 클라이언트와 직접 소통. 요청을 처리하는데 OWIN 문맥을 사용. 서버는 OWIN 문맥을 이해할 수 있도록 돕는 어뎁터 레이어가 필요.
  • 웹 프레임워크: 요청을 처리하는데 사용하는 어플리케이션을 OWIN에서 원활하게 구동할 수 있도록 돕는 독립적 컴포넌트. OWIN 문맥을 이해할 수 있는 어뎁터 레이어 필요.
  • 웹 어플리케이션: 웹프레임워크 위에서 개발 가능하며, OWIN 호환 서버에서 구동이 가능한 특정 어플리케이션.
  • 미들웨어: 서버와 어플리케이션 사이의 파이프라인을 통과해 구동되는 컴포넌트로 특정의 목적에 따라 응답과 요청을 점검, 라우팅 또는 수정할 수 있음.
  • 호스트: 서버 내에서 어플리케이션을 실행하기 위해 우선적으로 응답하는 어플리케이션 실행부. 특정 서버는 호스트의 역할도 수행함.

OWIN의 전체적인 흐름은 다음과 같다.

owin

서버를 통해 요청이 들어오면 호스트는 Startup 클래스에 정렬된 파이프라인을 따라 미들웨어를 실행한 후 어플리케이션을 실행한다. 어플리케이션 실행 후 응답 또한 미들웨어를 거쳐 빠져나간다. 미들웨어는 Task를 이용해 다음 파이프라인으로 컨텍스트를 넘겨준다. 각각의 미들웨어는 앞서의 정의처럼 응답과 요청을 조작할 수 있다.

OWIN 명세에서는 AppFunc라고 불리는 어플리케이션 대리자(delegate)를 통해 환경을 주고 받는다. 명세에서는 다음과 같이 환경과 Task로 구성되어 있다.

using AppFunc = Func<
    IDictionary<string, object>, // Environment
    Task>; // Done

환경은 크게 요청, 응답, 기타 데이터로 구분되는데 자세한 내용은 OWIN 스펙에서 찾아볼 수 있다. MS에서는 OWIN 명세를 기반으로 Katana라는 이름으로 프로젝트를 진행하고 있는데(Microsoft.Owin) 여기에서는 IOwinContext 인터페이스를 활용할 수 있다. 이 포스트의 예제에서도 IOwinContext를 사용하고 있다.

맛보기 코드

OWIN 어플리케이션

이 포스트에서는 누구나 따라해볼 수 있도록 Mono 환경을 기준으로 작성했다. IDE로는 Xamarin Studio를 사용했다.

Xamarin Studio을 실행해 새 솔루션을 생성한다. Console에서 self-host로 구동하는 예제이므로 Console Project를 선택한다. (Visual Studio를 이용하는 예제에서는 Web Empty Project를 사용해도 된다.4)

create solution

먼저 최신 패키지 설치를 위해 target framework를 Mono / .NET 4.5로 변경해야 한다. 해당 솔루션의 옵션에서 Build > General에서 변경할 수 있다.

options

project options

솔루션에 패키지를 추가한다. 솔루션에 오른쪽 클릭해서 Add > Add Packages... 를 클릭한다.

add packages menu

Show pre-release packages를 체크하고 Owin을 검색한다. 검색 결과에서 OWIN, Microsoft.Owin, Microsoft.Owin.Hosting, Microsoft.Owin.Host.HttpListener를 체크하고 Add Packages 버튼을 누른다.

add packages

설치가 완료되었으면 OWIN에서 엔트리 포인트가 될 Startup.cs 파일을 추가한다.

create file

이 파일의 내용은 다음과 같다. 5

using System;
using Owin;
using Microsoft.Owin;

[assembly: OwinStartup(typeof(OwinHelloWorld.Startup))]
namespace OwinHelloWorld
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Run (context => {
                context.Response.ContentType = "text/html";
                return context.Response.WriteAsync("<h1>It Works</h1>");
            });
        }

    }
}

Startup 클래스의 Configuration(IappBuilder app)메소드를 통해서 어떤 미들웨어에 어떤 순서로 접근하며(app.Use()) 최종적으로 어떤 어플리케이션이 실행되는지(app.Run()) 작성하게 된다.

[assembly: OwinStartup(typeof(OwinHelloWorld.Startup))] 부분은 이 Owin 코드가 컨테이너 형태로 실행될 때 엔트리 포인트를 지정해주는 부분이다. (이외에도 appsettings에 추가해주거나 owinhost.exe를 실행할 때 미리 선언한 identifier를 사용하는 방법이 있다.)

이제 이 인터페이스를 실질적으로 접근 가능하게 만들어줄 콘솔 어플리케이션을 작성한다. Program.cs를 열어 다음의 코드를 입력한다.

using System;
using Microsoft.Owin.Hosting;

namespace OwinHelloWorld
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            var url = "http://localhost:9000";
            using (WebApp.Start<Startup> (url)) {
                Console.WriteLine (url);
                Console.WriteLine ("Press enter to quit.");
                Console.ReadLine ();
            }
        }
    }
}

Microsoft.Owin.Hosting.WebApp으로 Startup 클래스를 구동한다. 이 과정에서 내부적으로 Microsoft.Owin.Host.HttpListener를 사용한다.

이제 프로젝트를 빌드하고 실행하면 다음과 같은 콘솔 화면이 나타난다.

console

그리고 해당 주소를 브라우저에서 열면 페이지를 확인할 수 있다.

helloworld

미들웨어 Middleware

미들웨어 간의 소통은 앞에서 말한 appFunc를 사용해 환경과 컨텍스트를 넘겨주는데 여기 예제에서는 Katana에서 제공하는 OwinMiddleware 클래스와 IOwinContext 인터페이스를 활용해 미들웨어를 작성할 것이다.

다음은 MyFirstMiddleware.cs의 코드다.

using System;
using System.Threading.Tasks;
using Owin;
using Microsoft.Owin;

namespace HelloWorldOwin
{
  public class MyFirstMiddleware : OwinMiddleware
  {
    public MyFirstMiddleware (OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context){
      context.Response.Write ("<!doctype html><html><body>");
      await Next.Invoke (context);
      context.Response.Write ("</body></html>");
    }
  }
}

OwinMiddleware 클래스를 상속받는 MyFirstMiddlewareInvoke(IOwinContext) 메소드를 사용해 해당 미들웨어에서 데이터를 핸들링 하거나 응답/요청을 변경하는 등의 코드를 작성할 수 있다.

다음은 MySecondMiddleware.cs의 코드다.

using System;
using System.Threading.Tasks;
using Owin;
using Microsoft.Owin;

namespace HelloWorldOwin
{
  public class MySecondMiddleware : OwinMiddleware
  {
    public MySecondMiddleware (OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context){
      context.Response.Write ("<header><h1>It works</h1></header>");
      await Next.Invoke (context);
      context.Response.Write ("<footer><a href=\"http://localhost:9000\">http://localhost:9000</a></footer>");
    }
  }
}

파이프라인의 흐름을 보여주기 위해서 그냥 예시 코드를 넣은 두번째 미들웨어다. 마지막으로 Startup.cs로 돌아가서 해당 미들웨어를 파이프라인으로 집어 넣는다.

using System;
using Owin;
using Microsoft.Owin;

[assembly: OwinStartup(typeof(HelloWorldOwin.Startup))]

namespace HelloWorldOwin
{
  public class Startup
  {
    public void Configuration(IAppBuilder app)
    {
      app.Use (typeof(HelloWorldOwin.MyFirstMiddleware));
      app.Use (typeof(HelloWorldOwin.MySecondMiddleware));

      app.Run (context => {
        context.Response.ContentType = "text/html";
        return context.Response.WriteAsync("<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>");
      });
    }
  }
}

app.Use()로 각각의 미들웨어를 연결했다. 앞서 예제와 동일하게 구동해보면 다음 결과를 볼 수 있다.

Owin with MiddlewareMiddleware Result

특별한 예제가 딱히 떠오르지 않아서 그냥 html 코드를 넣었는데 GitHub이나 nuget 리포지터리에 OAuth Autentication 같은 멋진 미들웨어가 많이 있어 위와 같이 간편하게 추가만 하면 사용이 가능하다.

여기까지 OWIN에 대해 살펴봤다. 아직 C#는 초보라서 깊이있게 글을 쓰지 못하는게 아쉽다. 하지만 앞으로의 발전이 더 기대되고 꾸준히 Follow-up 할 닷넷 프로젝트가 될 것 같다.

예제 코드

예제는 모두 Xamarin Studio로 작성했고 GitHub 리포지터리에서 내려받을 수 있다.

  • HelloWorldOwin : 위에서 작성한 예제 코드
  • HelloWorldOwinHost : owinhost.exe로 구동하는 예제 코드로 web.config등 Configuration 하는 방식이 조금 다르다.

더 읽을 거리

  • Python에서의 uWSGI와 유사한 접근 방식이다. 
  • OWIN에서 ASP.NET MVC를 구동할 수는 없지만 MVC에서는 Helios라는 프로젝트를 통해 OWIN을 사용할 수 있다. IIS의 파이프라인 중간에서 OWIN을 구동하게 돕는다. 
  • ASP.NET MVC에서 OWIN은 구동 가능하지만(Helios) 아직까지는 OWIN에서 ASP.NET MVC를 쓸 수는 없다. WebAPI는 OWIN 기반이라 현재도 활용 가능. MVC vNext에서는 OWIN도 지원될 예정이라고. 
  • Mono에 내장된 웹서버인 xsp는 아직 OWIN Startup을 인식하지 못해 Web Project로 시작하면 mscorlib 에러를 만나게 된다. 
  • 사실 Flask처럼 Python uWSGI를 기반으로 한 라이브러리/모듈을 사용해봤다면 익숙한 양식이다. 
  • 서비스나 웹사이트를 테스트를 하다보면 사용자에게 메일이 발송되는지 확인해야 하는 경우가 있다. 또한 실제로 운영되는 서비스를 테스트 환경에 놓고 테스트 하다가 메일이 사용자에게 발송되어 버리는 경우가 생길 수 있다. 물론 sendmail을 꺼두는 것도 방법이긴 하지만… Postfix를 사용하고 있다면 서버에서 발송되는 모든 메일을 하나의 메일 주소로 수신하게 설정할 수 있다. (Postfix가 서버에 없다면 설치하자.)

    먼저 /etc/postfix/recipient_canonical_map 파일을 다음과 같이 작성한다.

    /./    dev@haruair.com
    

    이 맵핑 파일에서 앞부분은 정규표현식이며 수신자가 정규표현식에 해당하면 뒷부분의 이메일로 리다이렉트 하도록 처리해준다. 정규표현식으로 여러 조건을 만들어 여러 이메일로 리다이렉트 할 수도 있다. 해당 파일을 저장하고 나서 /etc/postfix/main.cf를 열어 맵핑한 파일을 참조하도록 다음 설정을 추가한다.

    recipient_canonical_classes = envelope_recipient
    recipient_canonical_maps = regexp:/etc/postfix/recipient_canonical_map
    

    위 설정에서 recipient_canonical_classes는 기본값이 envelope_recipient, header_recipient인데 header_recipient는 수신자를 해당 리다이렉트 되는 이메일로 치환해버리기 때문에 확인하는데 불편함이 있어서 위와 같이 envelope_recipient만 설정한다. 두번째는 보는 것과 같이 맵파일의 경로를 설정해준다.

    수정을 완료하고 저장한 후 postfix 설정을 다시 불러오면 모든 과정이 끝난다.

    $ postfix reload
    

    postfix 설정에 관한 자세한 내용은 postfix 문서에서 확인할 수 있다.

    참고로 Windows에서는 Papercut을 켜두면 해당 서버에서 발송되는 메일이 실제로는 발송되지 않고 모두 로컬에 저장되어 그 내용을 확인할 수 있다.

    PHP를 디버깅하기 위해서는 Xdebug와 같은 확장을 서버에 설정해야 하고 리모트로 디버깅 하기 위한 클라이언트 프로그램이 요구된다. 이 글에서는 서버로 MAMP를 활용하며 클라이언트로 Sublime text를 활용한다.

    Xdebug 활성화하기

    MAMP에는 이미 Xdebug가 포함되어 있기 때문에 php.ini를 찾아 수정해주면 바로 활성화 할 수 있다. php.ini의 위치는 MAMP 기본 설치 시 /Applications/MAMP/bin/php/php<버전>/conf/php.ini에 있다. 해당 파일을 열어 가장 마지막줄로 이동하면 다음과 같이 주석처리 되어 있는 것을 확인할 수 있다.

    [xdebug]
    ;zend_extension="/Applications/MAMP/bin/php/php5.5.10/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so"
    

    PHP 버전에 따라 위 내용이 다를 수 있다. 해당 확장을 불러올 수 있도록 맨 앞에 ;를 지운다. 그리고 리모트 디버깅을 위해 다음과 같이 내용을 추가해 저장한다.

    [xdebug]
    zend_extension="/Applications/MAMP/bin/php/php5.5.10/lib/php/extensions/no-debug-non-zts-20121212/xdebug.so"
    xdebug.remote_autostart=1
    xdebug.remote_connect_back=1
    xdebug.remote_enable=1
    xdebug.remote_port=9000
    

    Sublime text에 Xdebug Client 설치 및 디버깅

    Cmd + Shift + P 를 눌러 Command Palette를 열고 Install Package를 실행해 Xdebug Client를 설치한다.

    설치 후 메뉴에서 Tools > Xdebug > Start Debugging을 실행해 디버깅 세션을 시작한다.

    세션이 정상적으로 시작되었다면 디버깅 하고자 하는 페이지에 다음과 같이 디버깅 쿼리 스트링을 붙여 다시 접속해보면 Sublime Text에서 디버깅이 가능한걸 확인할 수 있다.

    http://localhost/example.php?XDEBUG_SESSION_START=sublime.xdebug
    

    하단 4개의 창에서 Context, Watch, Stack, Breakpoint를 확인할 수 있으며 코드에서 오른쪽 클릭으로 Breakpoint나 watch expression을 추가해 확인할 수 있다.

    OSX에서 사용 가능한 클라이언트

    근래의 대다수 에디터와 IDE에서 기본적으로 내장되어 있어 현재 사용하고 있는 에디터나 IDE에 있는 기능을 먼저 확인해보도록 하자. 다음은 OSX에서 사용 가능한 standalone 클라이언트다.

    다른 브라우저를 사용하다가도 구글 크롬으로 돌아오게 되는 가장 큰 이유가 개발자 도구 때문이다. 물론 다른 브라우저에 내장된 개발자 도구들도 뛰어나지만 오래 사용하다보니 단축키나 사소한 기능들이 손에 익어버린 이유가 크다.

    최근들어 멀티커서나 재미있는 기능들이 추가되고 있어 나중엔 별도의 도구 없이도 개발할 수 있는 환경이 되지 않을까 생각이 든다.

    (이 글은 정말 소소소한 팁을 다루고 있다. 소소하다 못해 소소소한데 뭐 이런걸 포스팅하냐 하시면 제가 할 말이 없습니다. ;ㅅ;)

    크롬 개발자도구를 더 자세히 보고 싶다면 생활코딩 크롬 개발자도구편을 살펴보자.

    소소소한 팁

    개발자도구는 햄버거 버튼 > 도구 > 개발자 도구에서 열 수 있다. 맥에서의 단축키는 option(alt) + cmd + i로 열 수 있다.

    창 크기 확인하기

    개발자도구를 연 상태에서 창 크기를 변경하면 창 크기를 표시해준다.

    엘리먼트 순서 변경, 제거하기

    엘리먼트를 드래그-드롭으로 순서를 변경할 수 있다. delete 키를 누르면 제거할 수 있다.

    픽셀값 변경하기

    px, % 등의 값은 선택하고서 ↑, ↓ 키로 값을 변경할 수 있다. Shift + ↑, ↓ 는 10단위로 이동 가능하다.

    색상 변경하기

    css에서 색상을 보여주는 작은 색 박스를 클릭하면 컬러픽커로 색상을 변경할 수 있다.

    Pseudo class 바로 확인하기

    styles 탭에서 우측 상단에 pseudo class를 확인할 수 있는 셀렉터가 있다. 클릭해보면 4개의 pseudo class를 테스트 할 수 있다.

    물론 해당 엘리먼트에서 오른쪽 클릭해도 확인할 수 있다.

    일주일 동안 출퇴근에만 썼는데 500컷 가량을 찍었고, 그리고서 남기는 Ricoh GR 간단 사용기.

    Ricoh GR

    이렇게 생긴 Ricoh GR

    출시한지 좀 지난 카메라라서 세세하게 스펙을 나열하긴 그렇고 DP Reivew 링크로 대체.

    Ricoh GR의 명성은 한참 오래전부터 들어왔는데 드디어 영입했다. (왜 여태껏 주변에서 사용하는 사람이 없던건가. 왜 다들 S사 똑딱이를 사는건가!) 사실 GR 구입하기 전에 X100s와 GR 사이에서 엄청 고민했는데 (특히 뷰파인더 때문에) 6D의 서브로 X100s는 오버스펙일 것 같아서 GR로 결정했다. (가격도 그렇고. 그래 가격이 문제였지.)

    (덤으로 풀 프레임 카메라인 Canon EOS 6D랑 비교하면 너무 하드코어하긴 하지만, 주력이 6D인 관계로 6D와의 짤막 비교.)


    정확히 말하면 Ricoh GR Digital 5번째 버전이니까 Ricoh GRD5가 되야 하는데 브랜드 전략이 바뀌었는지 5번째 버전이 그냥 Ricoh GR이다.

    디지털 카메라는 포스트 프로덕션이 가능하기 때문에 색상을 이야기하는 것은 좀 적합하지 않게 느껴지지만 기본적으로 색상이 좀 다르다. 쨍하고 현실감 있는 색상이라기보다는 좀 더 필름 룩에 가까운 색을 보인다. 결과물을 보면 필름 스캔 결과물을 보는 기분이 든다. 모노크롬도 상당히 좋다.

    APC-S 크기의 센서를 탑재하고 있어서 광량이나 Depth of field에서 확실히 이득이 있다.

    광각이지만 어디서든 쓰기 좋은 환산 화각 28mm. 비네팅 없이 깔끔. 그리고 선예도가 정말 좋아서 사진의 섬세한 부분까지 놓치지 않는다. 이거 뭔가 광고 카피 느낌이지만 정말 그렇다.

    나는 노이즈를 신경쓰지 않는 쪽이라서 f/8, 1/400 맞춰두고 ISO 25600 까지 오르락 내리락 하게 두는 편이다. 컴팩트 카메라지만 야간에도 쓸 수 있다는건 대단한 성능이다. (같은 세팅으로 6D로 찍는 것보다는 센서 크기 때문인지 어둡다. 당연히 조리개를 좀 더 열면 밤에도 빠르게 찍을 수 있다. P모드로는 그냥 낮처럼 잘 찍힌다.)

    컴팩트 카메라인데 모든 수동 기능이 가능하고 측면에 하나, 후면에 둘 총 세개의 커스텀 가능한 버튼이 있다. 내 경우에는 Snap/AF 전환, Snap Distance, 측면은 ISO로 지정하고 사용하고 있다. 다이얼에 자신의 세팅을 3개까지 저장할 수 있는데 무려 이 커스텀 버튼 설정까지 저장이 됨. 생각해보면 컴팩트지만 기능이 워낙 많아서 메뉴 찾기 힘든 경향이 있다. 커스텀 버튼을 만든 이유가 아닐까.

    Snap Focus 기능. 특정 거리로 포커스를 고정해주는데 스트릿 촬영에 상당히 유용. AF에 약한 기기들은 이 기능을 본받았음 좋겠다. 언제든 포커싱 하느라 고생하는 일이 없다. 스냅 찍기엔 최고의 기능. (6D도 사용자 기능에서 half-press에 포커스를 꺼버리고 pre-focusing 상태로 사용하고 있다. 40mm 팬케익은 거리 표시가 없어서 불편하긴 하지만… 이건 다음에 얘기하기로 하고.)

    이건 단점인데 뷰파인더가 없다. 다음엔 꼭 외계인과 거래를 해서 RF를 내장했음 좋겠다.

    그래서 핫슈에 끼워서 쓰는 OVF가 있는데 고민하다가 구입했다. (Ricoh GV-1) 체감으로는 한 80cm 이내는 뷰파인더에서 보는 거랑 다르게 찍히는데 EVF가 아니니 어쩔 수 없고, 다행히 그 이상 거리에서는 별 차이 없이 찍힌다. SLR로 찍으면 미러 때문에 사실 촬영하는 순간의 모습을 볼 수가 없는데 OVF는 항상 보이니까 그게 장점. (뜬금없이 6D를 정리하고 X100s로 갈까 생각할 정도.) 다만 OVF의 가격이 깡패다. (사실 OVF는 어느 브랜드나 죄다 깡패다. 너네 왜그러니.)

    작은 크기도 어마어마한 장점 중 하나. 센서도 크고 광각인데 주머니 쏙 들어간다. 작은 크기지만 그립 크기는 적절해서 편하다. 손 끝에 닿는 부분이 좀 이질감이 들어서 테이프를 붙였다. 로고도 가리는 건 덤. (참고로 그립이 불편하면 thumb grip을 구입하는 것도 괜찮다고.)

    영상. 그러고보니 이걸로 영상을 안찍어봤다. DPReview에서 영상 점수가 엄청 낮은거 보니 안해봐도 될듯.

    플래시 동조가 1/400 까지 가능. 저렴한 수동 스트로보 하나 있으면 야간에도 막 찍어댈 수 있다. 내 경우엔 OVF를 사용하기 때문에 핫슈를 쓸 수 없는데 그냥 광동조로도 잘된다.

    참고로 적으면 내 스트로보는 Yongnuo에서 만든 YN-560-III인데 캐논의 스트로보랑 똑같이 생겼다. (물론 기능까지 같으면 좋겠지만 그럴리가 없지.) 한국어로 된 리뷰가 하나도 없지만 해외에서는 상당히 호평을 받는 스트로보. 장점은 아주 저렴한 가격, 빠른 리차지 속도. 물론 TTL 없고 고속동조 안된다. Yongnuo의 라인업은 참 풍성한데 기능 하나당 얼마씩 추가되는 수준이다. 그래도 최고 사양 모델이 캐논의 그 무지막지한 녀석보다 저렴. 물론 한국엔 Yongnuo보다 더 저렴하고 강력한 중소기업 제품들이 있다고 카더라.

    덧붙이면 6D는 포컬레인 셔터이기 때문에 1/160초가 최대 속도라 그 이상의 셔터 스피드로 찍으면 검은 잔상을 볼 수 있다. 그래서 캐논은 고속동조를 지원하는 플래시를 써야하고 그만큼 돈을 써야 하지. 하하하. 그래서 이 부분은 GR의 승리.

    총평

    대박. 만족도 98%. 모양만 컴팩트, 기능은 중급기 이상.

    다음 기종은 FF에 RF 뷰파인더 달아서 내줬음 좋겠다. 그렇게 내면 우주정복 가능.


    샘플은 아마 제대로 된 사용기를 작성하면 그때 쯤 넣게 될 것 같다. 6D는 제대로 된 리뷰할 생각조차 안한 이유가 기능이 없는게 자꾸 보여서 불평만 궁시렁 궁시렁 쓰게 될 것 같아서 못쓰고 있었는데…


    Ricoh GR을 동생에게 주고 왔는데 아쉬움을 담아 사진 블로그에 간단한 리뷰를 작성했다.

    평소에 짧은 메모를 많이 적는 편이다. 맥에서 메모를 위해 사용할 수 있는 다양한 도구가 많이 있긴 하지만 완제품인 어플리케이션을 내 취향대로 수정해 사용할 수 없는 부분이 가장 불편하다. 손에 딱 맞는, 쉽게 사용할 수 있는 프로그램을 찾아야하는데 그게 말처럼 쉽지 않다. 그래서 내 경우에는 오래 전부터 로컬에 나만 접근 가능한 워드프레스를 만들어 글쓰기 도구로 활용하고 있다.

    다양한 플러그인을 사용할 수 있고, 외부에 노출될 위험이 없으며, 추후 외부 공개로 전환하기에도 간편하다.1 만약 마크다운으로 작성하고 싶다면 일반 워드프레스를 사용하는 것과 동일하게 플러그인을 설치하면 완료된다. 특히 워드프레스가 지속적으로 업데이트 되고 있는 것도 큰 장점인데 각각의 글 변경사항을 관리해주는 부분, Just write 기능 등 글을 관리하는데 있어 유용하다. 물론 태그나 카테고리, 기간별 아카이빙 등 기본적인 기능들도 큰 도움이 된다. 워드프레스를 설치할 수 있는 환경은 MAMP라는 앱을 사용하면 쉽고 간편하게 진행 할 수 있다.

    MAMP 설치하기

    MAMP는 Mac을 위한 Apache, MySQL, PHP로 맥에서 웹서버를 구동해주는 앱이다. 일반적으로는 각각 설치하고 세팅해야 하는 번거로움이 있는데 MAMP는 단지 버튼 하나만 누르면 끄고 켤 수 있도록 돕는다.

    MAMP를 공식 사이트에서 내려받는다.

    MAMP Website

    내려받은 MAMP를 설치한다. 설치에는 980MB 정도를 요구한다. 내려받은 파일을 실행해 설치한다. 2

    MAMP Install

    설치가 완료되면 MAMP를 실행한다. 실행하면 MAMP PRO를 실행할 것인가 물어보는데 Check for MAMP PRO when starting MAMP 체크를 해제하고 Launch MAMP 클릭한다. MAMP PRO는 서버 관리에 있어 더 편리한 도구를 많이 제공하는데 지금은 MAMP면 충분하다.

    MAMP Management Panel

    이제 MAMP 관리 페널인데 버튼이 3개 있다. 우측에 Start Servers 버튼을 누르면 서버가 실행되고 서버 관리 웹페이지가 뜬다.

    MAMP Admin Webpage

    데이터베이스 생성하기

    워드프레스를 설치하기에 앞서 워드프레스의 데이터가 저장될 공간인 데이터베이스를 추가해야 한다. 위에서 본 서버 관리 웹페이지에 상단 메뉴에서 Tools > phpMyAdmin을 클릭한다.

    phpMyAdmin

    상단에 Databases 탭을 클릭, Create database 밑에 Database name에 wordpress를 입력하고 오른쪽 Create 버튼을 클릭한다. (다른 데이터베이스명을 사용해도 상관없다)

    Create a database

    워드프레스 설치하기

    wordpress website

    워드프레스 웹사이트에서 워드프레스를 내려받는다. 영어 또는 한국어 등 자신이 선호하는 버전을 설치하면 된다.

    Apache Tab

    내려받은 파일을 MAMP 안에 htdocs 폴더에 넣고 압축을 푼다. htdocs 폴더 경로는 /Application/MAMP/htdocs 인데 MAMP 관리 패널에서 Preferences… > Apache 탭으로 들어가 화살표 버튼을 누르면 MAMP 폴더가 나타난다. 거기 htdocs 폴더를 열어 거기에 받은 파일을 넣자.

    다음으로 wp-config.php 파일을 내려받아 압축 해제한 폴더 안에 넣는다. wp-config.php는 앞에서 추가한 데이터베이스와 워드프레스를 연결하기 위한 정보가 들어있는 파일이다. MAMP의 기본 아이디와 비밀번호, 앞서 데이터베이스명을 미리 입력해둔 파일이라 해당 위치에 잘 넣기만 하면 된다. (만약 위에서 생성한 데이터베이스 이름이 wordpress가 아니라면 이 파일을 열어 수정해야 한다.)

    여기까지 모두 완료되면 http://localhost:8888/wordpress 를 인터넷 주소창에 입력해 접속한다. 사이트명, 아이디, 비밀번호 등을 등록하는 절차를 걸쳐 워드프레스를 사용할 수 있게 된다.

    Welcome to wordpress

    아이디를 생성하고 로그인하면 이제 워드프레스를 로컬 환경에서 사용할 수 있게 된다.

    Wordpress main page

  • MAMP에서 아파치 설정을 해주면 동일한 네트워크 내에서 접속 가능한 형태로도 사용 가능하다. 
  • 중간에 관리자 권한을 위해 비밀번호를 입력하게 된다. 
  • 일반적으로 ssh에 접속하기 위해 다음과 같은 명령어를 사용한다.

    $ ssh edward@dev.haruair.com
    

    사실 단순해 보이지만 개발자는 게을러야 하므로 ~/.ssh/config에 설정을 작성해두면 더 짧게 사용할 수 있다. ~/.ssh/config가 없다면 빈 파일을 만들면 된다. 파일 내용은 다음과 같다.

    Host dev
        HostName dev.haruair.com
        User edward
    

    이렇게 작성하면 다음과 같이 접속 가능하다. (만약 동작하지 않는다면 퍼미션을 확인해주세요. ChangWan Jun님이 chmod 440 ~/.ssh/config 식으로 퍼미션 지정이 필요하다고 알려주셨습니다.)

    $ ssh dev
    

    해당 서버가 ssh key를 기본값인 id_rsa를 사용하고 있다면 접속에 문제가 없다. (ssh key를 생성하는 방법은 이 페이지를 참조) 하지만 각각 서버마다 다른 키를 사용하고 있다면 여전히 -i 플래그를 이용해야 해서 번거롭다.

    $ ssh dev -i ~/.ssh/haruair.dev
    $ ssh company -i ~/.ssh/edward.company
    

    각각 서버마다 어떤 키를 참조할지 config에 미리 작성해둘 수 있다.

    Host dev
        HostName dev.haruair.com
        User edward
        PreferredAuthentications publickey
        IdentityFile ~/.ssh/haruair.dev
    
    Host company
        HostName dev.haruair.company
        User edward
        PreferredAuthentications publickey
        IdentityFile ~/.ssh/edward.company
    

    내 경우엔 GitHub용 키를 별도로 생성해서 등록했는데 다음과 같이 쓸 수 있다.

    Host github.com
        User git
        IdentityFile ~/.ssh/haruair.github
    

    이렇게 등록해두면 다음과 같이 해당 주소의 ssh를 사용할 때 해당 키를 참조하게 된다.

    $ git clone git@github.com:haruair/some-repo.git
    

    2차 도메인 등의 경우, 다음과 같이 와일드카드로도 지정이 가능하다.

    Host *.haruair.com
        User edward
        PreferredAuthentications publickey
        IdentityFile ~/.ssh/haruair.dev
    

    config 파일은 상당히 세세한 범위까지 설정이 가능한데 그 내용은 ssh_config 메뉴얼에서 확인할 수 있다.

    ssh key를 생성하고 서버에 등록하는 방법은 복잡하지 않다. ssh-keygen으로 공개키/비밀키 한 쌍을 생성하고, 공개키 내용을 접속할 서버에 ~/.ssh/authorized_keys에 저장하면 해당 서버에 비밀번호 없이 ssh 접속이 가능하다.

    다음은 클라이언트에서 인증키를 생성하는 방법이다.

    $ ssh-keygen -t rsa -C "edward@haruair.com"
    Enter file in which to save the key (/home/user/.ssh/id_rsa): /home/user/.ssh/my_ssh_key # 키이름을 넣음
    Enter passphrase (empty for no passphrase): ********** # 최초 등록시 사용할 비밀문구를 입력함
    

    -t는 키의 타입이 rsa인지 dsa인지 정하는 플래그고 -C는 코멘트를 남기는 플래그다.

    위와 같이 입력하면 my_ssh_key와 my_ssh_key.pub이 생성되는데 *.pub 파일이 공개키로 서버에 등록하면 비밀번호 없이 접속이 가능해진다. 공개키의 내용을 확인하는 방법은 다음과 같다.

    $ cat /home/user/.ssh/my_ssh_key.pub
    

    위 명령어를 입력하면 터미널 상에 공개키 내용이 출력된다. 해당 내용을 복사해두자. 이제 이 내용을 서버에 접속해서 ~/.ssh/authorized_keys에 공개키를 추가해준다. 다음은 해당 서버에서 입력할 명령어다.

    $ cat >> ~/.ssh/authorized_keys
    (이 상태에서 복사한 공개키를 붙여 넣고 엔터를 눌러 줄을 바꾼 후 Ctrl+D를 누르면 저장된다.)
    

    이제 비밀번호 없이 인증키로 로그인이 가능하다.

    색상을 바꿔요

    눈에 편한 색상을 골라보세요 :)

    Darkreader 플러그인으로 선택한 색상이 제대로 표시되지 않을 수 있습니다.