User Tools

Site Tools


Sidebar

  • Learn about Wiki
  • Lectures
  • Study
  • Tips
    • study:web_programming:3_장

      루미너스 아키텍쳐

      프로젝트 관리

      프로젝트의 관리는 project.clj와 profiles.clj 2 개의 파일을 사용한다.

      sample project.clj

      프로파일

      자세한 설명 : 라이닝언 프로파일

      개관

      정의: 프로파일이란 하나의 프로젝트를 빌드, 릴리즈, 테스트, 개발 등, 프로젝트를 여러가지 단계 및 측면에서 필요한 설정을 선언적 방식으로 할 수 있도록 하는 프로젝트 관리 방법.

      프로파일에는 defproject(project.clj 파일에서 정의되는)에서 사용하는 모든 키-값을 사용할 수 있다. 프로파일에 정의된 키-값은 project 맵에 병합(merge)된다.

      프로파일 만들기

      다음 4가지 방식으로 프로파일을 만들 수 있다.

      1. 키로 정의하기
        • defproject에서 :profiles 키로 정의한다.
      2. profiles.clj 파일
        • git같은 버전관리툴에서는 무시되면서, 해당 프로젝트에만 특화된 설정을 하고 싶을 때 사용.
        • project.clj와 같은 디렉토리에 있어야 한다.
      3. ~/.lein/profiles.clj
        • 해당 유저에게만 특화된 프로젝트 설정을 할 때
      4. /etc/leiningen/profiles.clj
        • 시스템 전역에 걸쳐 적용

      키로 정의하기

      defproject에 :profiles 키에 맵으로 값을 할당한다.

      (defproject myproject "0.5.0-SNAPSHOT"
        :description "A project for doing things."
        :dependencies [[org.clojure/clojure "1.4.0"]]
        :profiles {:dev {:resource-paths ["dummy-data"]
                         :dependencies [[expectations "1.4.41"]]}})

      기본 프로파일

      프로젝트가 만들어지지 않은 아무 디렉토리에서 lein show-profiles 명령을 실행하면 기본적으로 존재하는 프로파일을 볼 수 있다.

      > lein show-profiles
      base
      debug
      default
      leiningen/default
      leiningen/test
      offline
      uberjar
      update
      user

      서브 프로파일

      기 정의된 프로파일로 다른 프로파일을 만들 수 있다. 이때는 프로파일 값으로 맵이 아니라 백터를 쓰고 구성하고 싶은 프로파일 명을 원소로 넣는다.

      {:shared {:port 9229, :protocol "https"}
       :qa [:shared {:servers ["qa.mycorp.com"]}]
       :stage [:shared {:servers ["stage.mycorp.com"]}]
       :production [:shared {:servers ["prod1.mycorp.com", "prod1.mycorp.com"]}]}

      루미너스의 프로파일 구성 방식

      (defproject guestbook "0.1.0-SNAPSHOT"
       
      ...
       
      :profiles
        {:uberjar {:omit-source true
                   :env {:production true}
                   :aot :all
                   :source-paths ["env/prod/clj"]
                   :resource-paths ["env/prod/resources"]}
         :dev           [:project/dev :profiles/dev]       ; (1)
         :test          [:project/test :profiles/test]     ; (2)
         :project/dev  {:dependencies [[prone "1.0.1"]
                                       [ring/ring-mock "0.3.0"]
                                       [ring/ring-devel "1.4.0"]
                                       [pjstadig/humane-test-output "0.7.1"]
                                       [mvxcvi/puget "1.0.0"]]
       
       
                        :source-paths ["env/dev/clj" "test/clj"]
                        :resource-paths ["env/dev/resources"]
                        :repl-options {:init-ns user}
                        :injections [(require 'pjstadig.humane-test-output)
                                     (pjstadig.humane-test-output/activate!)]
                        ;;when :nrepl-port is set the application starts the nREPL server on load
                        :env {:dev        true
                              :port       3000
                              :nrepl-port 7000}}
         :project/test {:env {:test       true
                              :port       3001
                              :nrepl-port 7001}}
         :profiles/dev {}
         :profiles/test {}})
      • (1) 에서 :dev 프로파일은 :project/dev과 :profiles/dev으로 구성된다.
      • (2) 에서 :test 프로파일은 :project/test와 :profiles/test로 구성된다.
      • project/dev와 project/test는 project.clj파일에서 정의한다.
      • profiles/dev와 profiles/test는 profiles.clj에서 정의한다.

      project/test 프로파일 보기

      lein show-profiles로 project/test 프로파일이 어떻게 설정되는지 볼 수 있다.

      > lein show-profiles project/test
      {:env {:test true, :port 3001, :nrepl-port 7001},
       :jvm-opts nil,
       :eval-in nil}

      실행 소스 파일 선택하기

      개발시에는 에러가 발생하면 에러 메시지가 자세하게 나오게 하는 것이 좋지만, 배포시에는 제한된 메시지만 뿌리게 하고 싶다. 하지만 개발시와 배포시의 실행을 코드상으로 구별하는 것은 또 다른 버그를 만들 수 있다. 이것도 프로파일을 사용하면 원하는 소스만을 해당 개발과 배포시에 구분해서 사용할 수 있다.

      루미너스에서 실행 파일 선택하는 방법

      :source-paths는 defproject의 키로서 프로젝트에서 실제 사용할 소스의 위치를 정의한다. 이 키가 루미너스에서는 root와 :uberjar, 그리고 :project/dev 에서 다음과 같이 설정되어 있다.

      • root - :source-paths [“src/clj”]
      • :uberjar - :source-paths [“env/prod/clj”]
      • :project/dev - :source-paths [“env/dev/clj” “test/clj”]

      개발시에는 env/dev에 있는, 배포시에는 env/prod 폴더에 있는, guestbook.config 이름공간을 사용한다.

      env/dev/guestbook/config.clj

      (ns guestbook.config
        (:require [selmer.parser :as parser]
                  [clojure.tools.logging :as log]
                  [guestbook.dev-middleware :refer [wrap-dev]]))
       
      (def defaults
        {:init
         (fn []
           (parser/cache-off!)
           (log/info "\n-=[guestbook started successfully using the development profile]=-"))
         :middleware wrap-dev})

      env/prod/guestbook/config.clj

      (ns guestbook.config
        (:require [clojure.tools.logging :as log]))
       
      (def defaults
        {:init
         (fn []
           (log/info "\n-=[guestbook started successfully]=-"))
         :middleware identity})

      어플리케이션 컴포턴트

      보통 웹 어플리케이션에서는 MVC 패턴을 사용하지만 루미너스에서는 뷰와 컨트롤러 사이의 구분이 엄격하지 않다. 오히려 관련된 코드는 같은 이름공간에 존재한다.

      하지만 클로저 웹 스택은 아주 유연하기 때문에 MVC 패턴 방식으로 구성할 수도 있다.

      루미너스에서의 컴포넌트

      • core: HTTP 서버를 실행하고 멈춘다.
      • handler: 클라이언트로부터 요청을 받아 응답을 하는 루트 핸들러.
      • routes: 여러 종류의 요청을 처리하기 위한.
      • db: 어플리케이션 데이타 모델과 프리젠테이션 레이어를 위한 데이타 모델.
      • layout: 어플리케이션의 레이아웃을 만든다.
      • middleware: 커스텀 미들웨어.

      core

      최초의 어플리케이션 구동과 서버 구동하는 코드들이 정의되어 있다.

      handler

      루미너스는 핸들러의 routing을 다음과 같이 분리되어 있다.

      • home-routes: 주요 레이아웃 라이팅(GET 메소드로 실제 클라이언트 요청 처리)
      • app-routes: csrf 사후 처리, not-found
      • app: wrap-base

      일반적으로는 다음과 같이 시작한다.

      (defroutes app-routes
        (GET  "/" [] (resource-response "index.html" {:root "public"}))
        (GET  "/widgets" [] (response [{:name "Widget 1"} {:name "Widget 2"}]))
        (route/resources "/")
        (route/not-found "Page not found"))

      init과 destroy 함수는 서버 시작과 종료시에 실행할 코드 정의한다.(이 2 함수는 handler가 아닌 core 이름공간으로 갈 필요가 있어 보인다)

      • init: 로거 시작, 컴포넌트 시작을 알림
      • destroy: 컴포넌트 종료를 알림

      컴포넌트 라이브러리로는 스튜 지에라의 Component가 아닌 mount 사용하고 있다.

      middleware

      커스텀 미들웨어를 정의한다.

      routes

      db

      환경 변수로 DB 설정한다.

      layout

      HTTP 응답을 위한 HTML 만들기.

      *app-context*는 요청의 :servlet-context나 혹은 환경변수의 :app-context로 동적으로 설정되면서 wrap-context 미들웨어에 적용된다.

      study/web_programming/3_장.txt · Last modified: 2019/02/04 14:26 (external edit)