갈루아의 반서재

Luminus 를 이용한 Clojure 방명록 만들기 (1)

Creating a new application

Leiningen 은 이미 설치되어 있다면, 다음의 명령으로 어플리케이션을 초기화할 수 있다.

설치 이전이라면 다음 링크를 참조 http://redhotkorea.tistory.com/1769

1
2
3
$ lein new luminus guestbook +h2
Retrieving luminus/lein-template/3.0.1/lein-template-3.0.1.pom from clojars
 
cs

이를 통해 H2 임베디드 데이터베이스 엔진을 지원하는 새로운 템플릿 프로젝트가 생성된다.


Anatomy of a Luminus application

새롭게 생성한 어플리케이션은 다음의 구조를 갖는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
fukaerii@133-130-107-97:~/guestbook$ tree
.
├── Capstanfile
├── dev-config.edn
├── Dockerfile
├── env
│   ├── dev
│   │   ├── clj
│   │   │   ├── guestbook
│   │   │   │   ├── dev_middleware.clj
│   │   │   │   └── env.clj
│   │   │   └── user.clj
│   │   └── resources
│   │       ├── config.edn
│   │       └── logback.xml
│   ├── prod
│   │   ├── clj
│   │   │   └── guestbook
│   │   │       └── env.clj
│   │   └── resources
│   │       ├── config.edn
│   │       └── logback.xml
│   └── test
│       └── resources
│           ├── config.edn
│           └── logback.xml
├── Procfile
├── project.clj
├── README.md
├── resources
│   ├── docs
│   │   └── docs.md
│   ├── html
│   │   ├── about.html
│   │   ├── base.html
│   │   ├── error.html
│   │   └── home.html
│   ├── migrations
│   │   ├── 20180821033932-add-users-table.down.sql
│   │   └── 20180821033932-add-users-table.up.sql
│   ├── public
│   │   ├── css
│   │   │   └── screen.css
│   │   ├── favicon.ico
│   │   ├── img
│   │   │   └── warning_clojure.png
│   │   └── js
│   └── sql
│       └── queries.sql
├── src
│   └── clj
│       └── guestbook
│           ├── config.clj
│           ├── core.clj
│           ├── db
│           │   └── core.clj
│           ├── handler.clj
│           ├── layout.clj
│           ├── middleware.clj
│           ├── nrepl.clj
│           └── routes
│               └── home.clj
├── test
│   └── clj
│       └── guestbook
│           └── test
│               ├── db
│               │   └── core.clj
│               └── handler.clj
└── test-config.edn
 
30 directories, 38 files
 
cs

루트 디렉토리의 주요 파일과 디렉토리에 대해 살펴보자.

The Source Directory
기본적으로 모든 코드는 src/clj 폴더에 위치한다. 어플리케이션 이름이 guestbook 이기 때문에, 해당 프로젝트의 루트 네임스페이스가 된다.  

GUESTBOOK
core.clj - 서버시작 및 종료 로직을 포함하는 어플리케이션의 시작점
handler.clj - 어플리케이션의 기본 루트 정의, 어플리케이션으로 들어가는 시작점 
layout.clj - 페이지의 컨텐츠를 렌더링하는 레이아웃 헬퍼를 위한 네임스페이스
middleware.clj - 커스톰 미들웨어를 포함하는 네임스페이스

GUESTBOOK.DB
db 네임스페이스는 어플리케이션 모델을 정의하고, 영속계층(persistence layer)을 다루기 위함이다.
core.clj - 데이터베이스와 상호작용하는 함수들을 저장

GUESTBOOK.ROUTES
routes 네임스페이스는 홈과 어바웃 페이지에 대한 컨트롤러와 라우트가 어디에 위치해있는지를 기숳한다. 인증이나 특정 워크플로우 등 라우트가 추가될 때 이 파일에 기술되어야 한다.
home.clj - 어플리케이션의 홈과 어바웃 페이지를 정의하는 네임스페이스

The Env Directory
환경에 특정된 코드와 리소스는 env/dev, env/test, 그리고 env/prod 경로에 위치한다. 개발하는 동안에는 dev 설정이, 테스팅 동안에는 test 설정이 사용된다. 그리고 prod 설정은 어플리케이션이 배포될 때 사용되낟. 

dev/clj
user.clj - REPL 개발 동안 실행하고자 하는 모든 코드를 위한 유틸리티 네임스페이스
guestbook/env.clj - 개발 설정 기본값 저장
guestbook/dev_middleware.clj - 생산 단계에서는 컴파일되어서는 안되는 개발용 미들웨어 포함

dev/resources
config.edn - 개발을 위한 기본 환경 변수
logback.xml - 개발 로깅 프로필을 구성하기 위한 파일 

test/resources
config.edn - 테스트를 위한 기본 환경 변수

prod/clj
guestbook/env.clj - 생산 환경설정을 포함한 네임스페이스

prod/resources
config.edn - 생산을 위한 기본 환경 변수 
logback.xml - 생산 로깅 환경설정 기본값

The Test Directory
어플리케이션 테스트를 위한 곳으로, 샘플 테스트 몇 가지는 이미 정의되어 있다.

The Resources Directory
어플리케이션에 포함된 정적 자원이 위치한 곳이다. 여기에 포함된 컨텐츠는 클라이언트에게 제공된다. 이미 생성된 CSS 리소스 등을 확인할 수 있다. 

HTML TEMPLATES
resources/html 디렉토리는 어플리케이션 페이지를 표현하는 Selmer 템플릿을 위한 것이다.
  • about.html - about page
  • base.html - base layout for the site
  • home.html - home page
  • error.html - error page template
SQL QUERIES
SQL 쿼리는 resources/sql 폴더에 위치한다.
queries.sql - SQL 쿼리와 연계된 함수 이름을 정의한다.

THE MIGRATIONS DIRECTORY
Luminus 는 마이그레이션을 위해 Migratus 을 사용한다. SQL 파일을 사용하여 이루어진다. 그리고 해당 파일은 관례적으로 파일명에 날짜가 붙고, 생성순으로 적용된다. 다음과 같다. 

20150718103127-add-users-table.up.sql - 테이블을 생성하기 위한 마이그레이션 파일
20150718103127-add-users-table.down.sql - 테이블을 삭제하기 위한 마이그레이션 파일


The Project File

앞서도 언급했듯이 의존성은 project.clj 파일을 업데이트함으로써 관리된다. 앞서 생성한 어플리케이션의 프로젝트 파일은 루트 폴더에 위치해있고, 다음과 같은 형태를 지닌다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
(defproject guestbook "0.1.0-SNAPSHOT"
 
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
 
  :dependencies [[clj-time "0.14.4"]
                 [com.h2database/h2 "1.4.196"]
                 [compojure "1.6.1"]
                 [conman "0.8.2"]
                 [cprop "0.1.11"]
                 [funcool/struct "1.3.0"]
                 [luminus-immutant "0.2.4"]
                 [luminus-migrations "0.5.2"]
                 [luminus/ring-ttl-session "0.3.2"]
                 [markdown-clj "1.0.2"]
                 [metosin/muuntaja "0.5.0"]
                 [metosin/ring-http-response "0.9.0"]
                 [mount "0.1.12"]
                 [nrepl "0.4.4"]
                 [org.clojure/clojure "1.9.0"]
                 [org.clojure/tools.cli "0.3.7"]
                 [org.clojure/tools.logging "0.4.1"]
                 [org.webjars.bower/tether "1.4.4"]
                 [org.webjars/bootstrap "4.1.3"]
                 [org.webjars/font-awesome "5.2.0"]
                 [org.webjars/jquery "3.3.1-1"]
                 [org.webjars/webjars-locator "0.34"]
                 [ring-webjars "0.2.0"]
                 [ring/ring-core "1.6.3"]
                 [ring/ring-defaults "0.3.2"]
                 [selmer "1.11.8"]]
 
  :min-lein-version "2.0.0"
  
  :source-paths ["src/clj"]
  :test-paths ["test/clj"]
  :resource-paths ["resources"]
  :target-path "target/%s/"
  :main ^:skip-aot guestbook.core
 
  :plugins [[lein-immutant "2.1.0"]]
 
  :profiles
  {:uberjar {:omit-source true
             :aot :all
             :uberjar-name "guestbook.jar"
             :source-paths ["env/prod/clj"]
             :resource-paths ["env/prod/resources"]}
 
   :dev           [:project/dev :profiles/dev]
   :test          [:project/dev :project/test :profiles/test]
 
   :project/dev  {:jvm-opts ["-Dconf=dev-config.edn" "--add-modules" "java.xml.bind"]
                  :dependencies [[expound "0.7.1"]
                                 [pjstadig/humane-test-output "0.8.3"]
                                 [prone "1.6.0"]
                                 [ring/ring-devel "1.6.3"]
                                 [ring/ring-mock "0.3.2"]]
                  :plugins      [[com.jakemccrary/lein-test-refresh "0.23.0"]]
                  
                  :source-paths ["env/dev/clj"]
                  :resource-paths ["env/dev/resources"]
                  :repl-options {:init-ns user}
                  :injections [(require 'pjstadig.humane-test-output)
                               (pjstadig.humane-test-output/activate!)]}
   :project/test {:jvm-opts ["-Dconf=test-config.edn" "--add-modules" "java.xml.bind"]
                  :resource-paths ["env/test/resources"]}
   :profiles/dev {}
   :profiles/test {}})
cs

위에서 보시다시피 project.clj 파일은 key/value 쌍으로 이루어진 클로저 리스트이다. 해당 프로젝트에 새로운 라이브러리를 추가하는 것이 가장 일반적인 역할이다. 이러한 라이브러리는 :dependencies 벡터를 사용하여 특정된다. 새로운 라이브러리를 사용하기 위해서는 의존성을 이 파일에 추가하기만 하면 된다. 

:plugins 벡터에 포함된 아이템은 추가적인 기능을 제공하기 위해 사용된다.

:profiles 에는 개발이든 생산단계든 초기화에 필요한 서로 다른 프로젝트의 설정 파일이 포함된다.