글의 분량 상 맥을 기준으로 합니다. 윈도우라고 하더라도 순서는 같으며, 핵심이 되는 act
는 윈도우에서도 구동이 되기 때문에 아무런 문제가 없습니다.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install Homebrew
brew install git
# Install git
그리고 도커를 구동하기 위해서 Docker Desctop을 홈페이지에서 다운 받은 후 설치한 후 설정을 체크합니다.
터미널에서 docker
명령어가 작동하는지 확인한 후 작동하지 않으면 .zshrc
파일에서 아래를 추가해 줍니다.
export PATH=$PATH:~/.docker/bin
source .zshrc
그 후 마지막으로 act를 설치합니다.
brew install act
# Install act
깃헙 액션이 있는 레포지토리를 클로닝 합니다. 만약 그런 레포지토리가 없거나 알지 못한다면 아래와 같이 해 보세요.
git clone https://github.com/cable8mm/n-format
cd n-format
그 후 act -l
명령어를 실행하면 깃헙 액션 리스트가 보입니다.
INFO[0000] Using docker host 'unix:///var/run/docker.sock', and daemon socket 'unix:///var/run/docker.sock'
Stage Job ID Job name Workflow name Workflow file Events
0 phplint phplint PHP Linting (Pint) lint.yml workflow_dispatch,push
0 build build Test test.yml push,pull_request
Job name이 phplint
와 build
가 보이는데요, 잡 이름으로 실행하세요.
act -j phplint
act -j build
로컬에서 모든 깃헙 액션이 실행되는 것은 아닙니다. 예를 들어서, 제가 즐겨 쓰는 stefanzweifel/git-auto-commit-action@v4
액션은 코딩 스타일을 검사해서 수정한 후 자동으로 커밋해 주는 액션인데요, act로 실행할 경우 오토커밋이 작동하지 않기 때문에 이 단계에서 멈춥니다.
물론 깃헙과의 인증 프로세스를 만든다면 이런 문제가 없겠지만, 우리가 하려는 것은 로컬에서 구동하는 것이지 깃헙과의 연동이 아니겠죠.
다른 사람이 만들어 놓은 액션을 그대로 사용한다면 로컬에서 깃헙 액션을 구동하는 것이 의미가 없겠지만, 깃헙 액션으로 CICD를 구현하는 등 직접 액션을 만든다면 깃헙에 코드를 푸쉬하고 액션을 구동하고 수정하고 다시 푸쉬하고, 이런 작업을 몇일 동안 반복하는데 로컬 구동은 많은 도움이 됩니다.
도커는 코딩할 때에는 특히 맥 사용자라면 그다지 도움이 되지 않을 수도 있으나, 배포나 테스팅의 경우에는 워크플로(workflow)를 만드는데 도움이 됩니다.
도커의 전문가가 될 필요는 없지만, 도커 사용 방법은 알아두는걸 추천합니다.
]]>라라벨 Valet은 커맨드 만으로 mysql, dnsmasq, php, nginx, 그리고 https와 NAT 외부에서 접속할 수 있게 하는 등 다른 프레임워크에 비해서 굉장히 편한 개발환경을 만들어 줍니다. 10분도 안되서 개발 환경을 만들 수 있죠.
반면 라라벨 Herd는 라라벨 Valet을 건들이지 않고도 더 편하고 빠른 개발환경을 만들 수 있으며, php나 node 버전 업데이트 등도 쉽게 관리할 수 있고 맥 네이티브 UI 를 제공하므로 사용하지 않을 이유가 없습니다.
다만, 에러가 생길 경우 Herd는 생긴지 얼마 되지 않기 때문에 조금 까다로우며, 이 글에서 다루는 에러도 해결을 하는데 8시간이나 걸렸습니다.
라라벨 Herd는 유료인 Pro 버전을 제공하는데요, 그 경우 XDebug를 자동으로 관리 해 줍니다. 무료 버전의 경우 아래와 같이 XDebug를 설정할 수 있죠.
zend_extension=/Applications/Herd.app/Contents/Resources/xdebug/xdebug-83-arm64.so
xdebug.mode=debug,develop
xdebug.start_with_request=yes
xdebug.start_upon_error=yes
공식 문서에 따르면 위의 코드를 php.ini
파일 안에 넣습니다. php.ini
는 화면 최 상단 Herd 아이콘을 클릭 후 나오는 Show php.ini
을 클릭하면 finder가 바로 뜹니다.
그런데, 위와 같이 하더라도 Xdebug와 php가 연결이 되지 않을 때가 있습니다.
~ herd restart
Xdebug: [Step Debug] Could not connect to debugging client. Tried: localhost:9003 (through xdebug.client_host/xdebug.client_port).
Xdebug: [Step Debug] Could not connect to debugging client. Tried: localhost:9003 (through xdebug.client_host/xdebug.client_port).
Restarting DNSMasq...
Restarting PHP 8.2...
Restarting Nginx...
Herd services have been restarted.
Herd 재시작을 하면 DNSMasq, PHP, Nginx 모두 리스타트가 되지만, Xdebug는 작동하지 않습니다. 이 경우 어떻게 해결할까요?
라라벨 Herd의 설명대로 php.ini
에 넣고 아래 한 줄을 더 추가 해 줍니다.
xdebug.log_level=0
이 명령어는 실행 로그를 멈추라는 뜻입니다.
이후 라라벨 Herd를 재시작하면 Xdebug가 웹이던 cli던 제대로 작동됨을 확인할 수 있습니다.
전 라라벨 Herd가 라라벨 valet에 맥 UI를 올린 것이라고 생각했습니다만, 라라벨 Herd는 valet과는 완전히 다르게 개발 환경을 관리 해 줍니다. 물론 Herd는 valet과 충돌되지 않는다고 이야기하지만, 전 이번 에러를 해결하면서 valet을 완전히 삭제했으며, 기존에 설치된 php 및 pecl 모두 삭제를 했습니다.
동일한 일을 두가지 프로그램이 할 경우 특정한 상황에서 문제를 발생할 수 있으니까요.
만약 맥에서 php 개발이 처음이라면 valet을 설치하지 말고 Herd를 설치하는 것이 더 쾌적한 개발 환경을 만들 수 있습니다.
]]>Jekyll(/ˌdʒek.əl/)은 한국 발음으로 제컬이라고 하며, 지킬박사와 하이드에서의 그 지킬이 Jekyll 입니다. Jekyll은 데이터베이스를 사용하지 않고, 블로거가 작성한 마크다운 타입의 문서를 HTML로 변환해서 보내는 역할을 하는 일종의 사이트 빌더입니다.
Transform your plain text into static websites and blogs.
- Jykyll
깃헙이 공식적으로 지원하고 있으며, Jekyll을 사용하면 무료로 깃헙 페이지에 나의 블로그를 만들고, 도메인을 연결할 수 있습니다.
내가 블로깅 툴을 운영하면서 필요했던 것은 세가지 입니다.
내가 사용해 본 블로깅 플랫폼은 wordpress
, tattertools
, tistory
, naver blog
, naver post
, google blogger
, gitbooks
, Wix
등 입니다.
이 모든 툴들은 데이터베이스를 이용하며, 디자인 코드가 나의 글에 포함되기 때문에 콘텐츠에 집중하기가 쉽지 않습니다. 이 문제를 해결하기 위해서 해외에서는 Medium
이나 dev.to
등이 나오기도 했습니다.
내가 필요한 두가지 기능을 지원하는 블로깅 플랫폼은 없었는데요, 순수 HTML 개발 환경을 추구하는 JamStack
을 공부하면서 알게 된 웹사이트 제네레이터 중 몇가지가 눈에 띄었습니다.
이 세가지 플랫폼은 모두 깃헙 페이지에 내 글을 올리고 도메인을 연결할 수 있습니다. 또한 마크다운으로 글을 쓰면 대부분의 것들이 자동으로 이루어 집니다.
Jekyll is one of the most mature static site generators around and has been a great tool to use — in fact, before Docusaurus, most of Facebook’s Open Source websites are/were built on Jekyll! It is extremely simple to get started. We want to bring a similar developer experience as building a static site with Jekyll.
- docusaurus 도움말 중 디자인 철학 섹션 일부 인용
특히 Docusaurus는 메타(구 페이스북)가 Jekyll로 사이트를 제작하다가 그 이상의 기능이 필요해서 직접 만들어서 배포하는 것으로 웹사이트 빌더로 손색이 없습니다.
전 너무 많은 기능을 좋아하지 않습니다. 제가 원하는 것은 마크다운으로 문서만 만들면 나머지는 자동으로 배포가 되어야 하며, 서버 관리 포함해서 아무런 행위도 필요하지 않아야 한다는 것입니다.
Jekyll을 선택한 이유는 깃헙이 공식적으로 지원하는 유일한 플랫폼이라는 점이지만, 제작 철학도 저와 잘 맞았습니다. Jekyll의 개발 커뮤니티를 보면 사용하는 개발자들이 여러가지 제안을 하지만, 글쓰기 작업에 부가적인 행위가 필요할 경우 거부됩니다.
즉, 오랜 기간이 지났지만 여전히 Jekyll는 마크다운을 만드는 것으로 모든 작업이 마무리 됩니다.
전 문서를 작성하는 도구로 Visual Studio Code + Markdown Preview 를 사용하며, 자동화 툴로 아래의 것들을 이용합니다.
블로깅을 하게 되면 디자인과 기능에 상당히 신경이 쓰입니다. 그래서 내 글에 기능과 디자인 코드가 포함됩니다.
임계점이 넘어가면 내 글은 이미 글이 아니라 브로셔가 되어 가며, 블로그 도구를 이전할 수도 없게 되며, 최종적으로는 글을 작성하지 않게 됩니다.
마크다운은 글의 색깔도 바꿀 수 없습니다. 타이틀이 아니면 폰트 크기도 키울 수 없죠. 이런 제약은 모바일이던 컴퓨터던 보는 사람이 편하게 볼 수 있는 기능을 플랫폼에서 추가할 수 있게 해 줍니다.
그리고, 웹 편집기에 비해서 비교도 안되게 편한 마크다운 편집기를 컴퓨터에 설치해서 글을 쓰는 것은 최고의 경험을 제공합니다.
이 것이 제가 돌아돌아 Jekyll로 온 이유입니다.
Jekyll가 어떻게 관리되고 있는지는 레포지토리를 오픈해 놨으니 누구나 볼 수 있습니다.
]]>Gradle
의 손을 들어주면서 Ant
와 Maven
보다 점유율을 높이고 있습니다. Gradle
에서 버전과 그 밖의 것들을 이야기 해 보겠습니다.
편의상 패키지매니저라고 언급했으나, Gradle은 빌드 매니저입니다. 패키지 관리는 Maven의 것을 이용하고 있습니다. 하지만, 우리가 패키지를 사용할 때 Gradle을 통해서 선언하기 때문에 빌드로 Gradle을 사용한다면, 패키지 선언도 Gradle을 사용해야 하므로, 사용하는 입장에서 패키지 의존성을 Gradle이 해결하는 느낌을 받습니다.
반면 패키지 자체를 개발할 경우에는 Gradle의 Maven Publish Plugin을 이용해서 배포할 수 있습니다.
먼저 아래의 선언(declaration)을 보시죠.
dependencies {
implementation("org.slf4j:slf4j-api:1.7.15")
}
org.slf4j:slf4j-api
는 패키지 이름이고, 1.7.15
이 버전입니다. 정확히 1.7.15버전을 설치하라는 의미인데요, 보통은 이렇게 쓰지 않고 1.7.x 패키지 중 높은 버전으로 설치하라고 선언합니다.
implementation("org.slf4j:slf4j-api:1.7.+") // 1.7.x 중 높은 버전
implementation("org.slf4j:slf4j-api:1.+") // 1.x.x 중 높은 버전
implementation("org.slf4j:slf4j-api:[1.1, 2.0)") // 1.1.x 중 높은 버전 혹은 2.x 중 2.0이 아니며 높은 버전
implementation("org.slf4j:slf4j-api:[1.1, [2.1") // 1.1.x 중 높은 버전 혹은 2.1.x 중 높은 버전
괄호를 이용한 버전 범위 선언은 Maven에서 사용하는 스타일인데요, 여전히 Gradle에서도 사용할 수 있습니다.
만약 버전에 관계없이 최신 버전을 선언할 경우 latest.integration
혹은 latest.release
을 사용할 수 있습니다.
Spring initializr에서 스켈레톤을 만들 경우 build.gradle
파일을 보면 버전 표기가 되어 있지 않습니다.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Gradle 에서는 매우 큰 프로젝트의 경우 버전을 표기하지 말고 constraints
즉 의존성을 이용하라고 권장합니다.
dependencies {
implementation("org.springframework:spring-web")
}
dependencies {
constraints {
implementation("org.springframework:spring-web:5.0.2.RELEASE")
}
}
단순히 버전을 표기하지 않으면 저장소에서 가장 최신의 버전을 다운로드 합니다. 그리고, Spring Boot의 경우 버전에 관한 내용은 spring-boot-starter-parent 의 spring-boot-dependencies에 정의되어 있습니다.
Gradle에서 버전을 업데이트하는 명령어는 아래와 같습니다.
./gradlew refreshVersions
의존성이 해석된 다운로드 된 버전은 Binary Reposity
라는 곳에 저장되며, 이 폴더는 보통 프로젝트가 아닌 컴퓨터에 저장되며, ~/.gradle/caches
폴더에 저장됩니다.
gradle 프로젝트를 만들 경우 gradle init
명령어로 프로젝트에 필요한 폴더와 파일들을 만들 수 있습니다.
참고로 Gradle은 빌드매니저인 만큼 tasks
라는 명령어도 관리를 해야 하는데요, 명령어의 집합을 plugins 라는 이름으로 관리합니다.
plugins {
java
id("org.springframework.boot") version "3.2.3"
id("io.spring.dependency-management") version "1.1.4"
}
스프링 부트를 설치하면 build.gradle
파일 가장 위에 plugins
가 선언되어 있는데요, 각 패키지에서 만든 태스크(일종의 명령어)가 들어있습니다. 스프링 부트를 실행하는 bootRun
도 여기에 정의되어 있기 때문에 gradlew bootRun
으로 스프링 부트를 구동할 수 있게 됩니다.
PHP의 composer나 Node의 npm, yarn 은 스크립트 언어이기 때문에 빌드를 할 필요가 없지만, 자바는 컴파일 언어이기 때문에 패키지 제작자가 빌드 시스템에 맞는 빌드 스크립트를 제작해 줄 필요가 있습니다.
쉽게 이야기하자면 하나의 프로그램으로 맥과 윈도우 양쪽에 배포한다면 코드는 그대로지만, 빌드와 아티펙트 배포 등의 빌드 스크립트는 두개를 작성해야 하는 것과 비슷합니다.
자바는 전세계 모든 디바이스에서 구동을 하기 위해 만들어 졌는데요, 그것을 구현하기 위해서 프로그래머는 프로그램을 제작하는 것 이상으로 수 많은 빌드 시스템에서 빌드가 제대로 되는 것을 보장해야 하기 때문에 자바 생태계는 Node나 PHP, Python 등의 스크립트 언어에 비해서 생태계가 빠르게 확장되지는 않으며, 커뮤니티 보다는 기업 위주의 생태계가 만들어 지는 이유이기도 합니다.
물론 이 것은 자바에만 있는 것이 아니라 C, C++, C# 등 빌드가 필요한 모든 언어들에 생기는 공통의 문제입니다. 이 문제를 해결한 golang은 빌드 문제를 배포시스템에서 완전히 해결하는 구조이기 때문에 컴파일 언어임에도 불구하고 매우 빠르게 생태계가 만들어 지고 있습니다.
]]>스프링의 공식 홈페이지에서는 특정 IDE를 다루지는 않지만, 주로 소개하는 IDE는 아래 네가지 입니다.
이 중 Theia 는 점유율이 낮고, 공식문서에서도 제외되는 경우가 많기 때문에 앞의 세가지 IDE만을 다루겠습니다.
Java 관련 개발의 최고의 도구라고 할 수 있습니다. 기업용 도구인 넷빈스(NetBeans)가 있었지만, 넷빈스를 보유했던 썬 마이크로시스템즈(Sun microsystems)가 오라클에게 인수된 후 넷빈스는 2016년에 아파치에 기부되었고, 아파치 인큐베이터에서 관리되고 있습니다. 아파치는 최고의 백엔드 시스템을 론칭한 이력이 있으나, 컨슈머용이나 개발자용 UI 도구를 운영하기에는 다소 보수적인 면이 있습니다.
반면 IntelliJ를 만들고 판매하는 JetBrains는 과거 델파이가 누렸던 영광을 재현하는데 성공하는 것으로 보이며, Apple에는 XCode, Microsoft에는 Visual Studio가 있었지만, 다른 나머지 기업들이 사용했던 Eclipse의 불편함을 각 개발 플랫폼 별로 제품으로 만들어 판매하고 있다는 점입니다.
지금까지 자바 개발 IDE에 있어서 최고의 툴은 단연 IntelliJ 라고 할 수 있습니다. 한가지 단점은 개인이 사용하기에는 라이센스 비용이 있습니다.
IDE | 1년 구독 금액(개인) | 1년 구독 금액(기업) |
---|---|---|
IntelliJ | US $169.00 | US $599.00 |
Visual Studio | Free(Community vesion) | US $250.00 |
개인에 한해서라면 Unity, Android Studio, XCode, Visual Studio Code 등 대부분의 IDE가 무료라는 것을 생각한다면 IntelliJ 의 유료 정책은 다소 아쉽지만, 자바 개발에 있어서 압도적인 효율과 새로운 기술을 가장 빠르게 적용해 준다는 것을 고려한다면 충분한 가치가 있습니다.
자바나 스프링을 주력 개발 언어와 플랫폼으로 사용한다면 최고의 선택입니다.
스프링 공식 홈페이지에서는 예전에는 Eclipse나 STS(Spring Tool Shite)를 우선했습니다. 예를 들어, 가이드가 도큐먼트에서 IDE를 설명할 때 Eclipse나 STS가 첫번째로 묘사가 되었는데요, 이 부분이 미묘하게 바뀌고 있습니다.
이미 STS라는 Eclipse를 기반으로 한 단독 IDE는 소개하고 있지 않습니다. 그리고, 도큐먼트에서도 이 자리를 Visual Studio Code(VSCode)가 대치하고 있습니다.
따라서, 현재 VSCode를 이용해서 스프링 부트 개발환경을 만드는데는 심각한 문제는 없습니다. 오히려 Eclipse 기반의 툴이 UI에서 모든 기능을 구현하기 때문에 IDE에서 지원하지 않는 기능은 사용할 수 없지만, VSCode는 일반적으로 Extension과 커맨드를 동시에 사용하기 때문에 이득이 있는 경우도 있습니다.
만약 여러분의 개발 스택이 자바에 국한되지 않고, IntelliJ에 매월 혹은 매년 지불할 가치가 적거나 없다고 생각한다면, VSCode가 최고의 선택입니다.
IntelliJ와 마찬가지로 Spring Tools 4는 Eclipse 기반으로 만들어 졌지만, 느립니다. 그런데 더 큰 문제가 있습니다.
이클립스라는 도구는 자바로 만드는 모든 개발을 할 수 있도록 설계되었고, 그 부분은 아직까지 유지되고 있는데, 문제가 되는 부분이 바로 workspace라는 개념입니다.
VSCode의 경우 사실 workspace, project라는 개념이 없습니다. 편의성을 위해서 폴더를 project라고 부르고 있으며, project로써 하는 모든 것은 확장에서 처리합니다.
A Visual Studio Code “workspace” is the collection of one or more folders that are opened in a VS Code window (instance).
반면 이클립스의 workspace가 하는 일은 의외로 많은데요, 이클립스 자체가 필요한 모든 정보를 workspace의 .metadata
폴더에 넣고, 이클립스를 실행할 때 마다 어떤 workspace를 사용할지에 대한 선택을 강요합니다. 그리고, 동일한 workspace 내의 projects는 서로 Linking이 되죠.
이 부분이 문제가 되는 이유는 최근의 CICD 환경에서는 소스에서 프로그램을 만들기 위한 build(빌드))라는 절차가 자동화가 되고, 빌드에 필요한 모든 정보가 project 내에 설정파일로 넣는데, workspace라는 존재가 이를 방해합니다.
IntelliJ는 이런 문제 때문에 더이상 workspace를 개발자에게 강요하지 않습니다. 다른 대부분의 IDE도 강제하고 있지 않습니다. 반면 Spring Tools 4 는 workspace를 git에 넣을 방법이 모든 프로젝트를 단일 레포지토리에 넣는 것이므로 소스 저장소 관리가 매우 복잡해 집니다.
이런 이유로 학습으로서의 목적이 아니면 Spring Tools 4 for Eclipse는 추천하지 않습니다. VSCode라는 대체제도 있으니까요.
만약 기존의 프로젝트가 Eclipse과 강력히 결합되어 있다면, 빌드를 자동화하기 위해서 별도의 담당자를 배정해야 합니다. 그 만큼 Eclipse의 workspace는 협업과 소스코드 관리 및 배포에 있어서 위험할 수 있습니다.
]]>http://localhost:8080
이 아닌 https://spring-boot.test
와 같은 도메인으로 개발할 수 있는 방법을 소개합니다.
웹사이트를 개발할 때 localhost
나 127.0.0.1
로 테스트를 하게 되면 쿠키와 세션, 그리고 카카오 로그인과 같은 외부 SDK와의 연동 문제 등이 생길 수 있습니다. 따라서, ssl과 커스텀 도메인은 라라벨 에코시스템에서는 필수이지만, 다른 프레임워크에서는 공식 문서에서도 이 부분을 다루지 않습니다.
이 글에서는 라라벨 발렛을 이용해서 스프링 부트를 로컬에서 띄우는 방법을 설명합니다.
Laravel Valet을 설치한 후 아래의 순서대로 따라 하세요.
valet secure
를 실행합니다cd spring-boot
valet secure
Valet은 간단한 커맨드 만으로 브라우져에서 https://spring-boot.test 로 접속을 할 수 있게 만들어 줍니다.
Nginx 설정파일을 에디터로 열어주세요.
code /Users/[MAC_NAME]/.config/valet/Nginx/spring-boot.test
이제 Valet의 Nginx 설정파일인 spring-boot.test
파일에서 가장 상단에 다음을 추가합니다.
map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default off;
}
그리고, 아래의 코드를 찾아서
location / {
rewrite ^ "/Users/[MAC_NAME]/.composer/vendor/laravel/valet/server.php" last;
}
이렇게 수정합니다.
location / {
expires $expires;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
proxy_pass http://127.0.0.1:8080; # set the adress of the Spring Boot instance here
}
설정을 변경한 후 valet restart
실행 후 https://spring-boot.test 로 접속을 하면 http://127.0.0.1:8080 으로 접속됩니다.(proxy_pass)
자, 이제 스프링 부트 프로젝트를 실행합니다.
./gradlew bootRun
브라우져에 https://spring-boot.test 를 입력하면 스프링 부트 웹사이트를 볼 수 있습니다!
개발할 때 도메인을 이용해야 하는 이유는 인증 관련 작업을 할 경우 IP나 localhost의 경우 개발을 하기가 매우 어렵기 때문입니다. 특히 카카오 로그인 등의 경우는 개발 자체가 불가능할 때도 있습니다.
부가적으로 Valet에는 ngrok
나 expose
를 이용해서 외부에서도 접속할 수 있거나 하는 기능이 있기 때문에 개발 편의성이 높아지는 장점도 있습니다.
라라벨 발렛을 사용하지 않아도 Ngnix나 Apache를 이용해서 리버스 프록시를 구성할 수 있습니다.
다음은 spring-boot.test
설정파일 전문입니다.
map $sent_http_content_type $expires {
"text/html" epoch;
"text/html; charset=utf-8" epoch;
default off;
}
server {
listen 127.0.0.1:80;
#listen 127.0.0.1:80; # valet loopback
server_name demo-for-spring-boot.test www.demo-for-spring-boot.test *.demo-for-spring-boot.test;
return 301 https://$host$request_uri;
}
server {
listen 127.0.0.1:443 ssl;
#listen VALET_LOOPBACK:443 ssl; # valet loopback
server_name demo-for-spring-boot.test www.demo-for-spring-boot.test *.demo-for-spring-boot.test;
root /;
charset utf-8;
client_max_body_size 512M;
http2 on;
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
internal;
alias /;
try_files $uri $uri/;
}
ssl_certificate "/Users/cable8mm/.config/valet/Certificates/spring-boot.test.crt";
ssl_certificate_key "/Users/cable8mm/.config/valet/Certificates/spring-boot.test.key";
location / {
expires $expires;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1m;
proxy_connect_timeout 1m;
proxy_pass http://127.0.0.1:8080; # set the adress of the Node.js instance here
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log "/Users/cable8mm/.config/valet/Log/nginx-error.log";
error_page 404 "/Users/cable8mm/.composer/vendor/laravel/valet/server.php";
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass "unix:/Users/cable8mm/.config/valet/valet.sock";
fastcgi_index "/Users/cable8mm/.composer/vendor/laravel/valet/server.php";
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME "/Users/cable8mm/.composer/vendor/laravel/valet/server.php";
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
}
server {
listen 127.0.0.1:60;
#listen 127.0.0.1:60; # valet loopback
server_name demo-for-spring-boot.test www.demo-for-spring-boot.test *.demo-for-spring-boot.test;
root /;
charset utf-8;
client_max_body_size 128M;
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
internal;
alias /;
try_files $uri $uri/;
}
location / {
rewrite ^ "/Users/cable8mm/.composer/vendor/laravel/valet/server.php" last;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log "/Users/cable8mm/.config/valet/Log/nginx-error.log";
error_page 404 "/Users/cable8mm/.composer/vendor/laravel/valet/server.php";
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass "unix:/Users/cable8mm/.config/valet/valet.sock";
fastcgi_index "/Users/cable8mm/.composer/vendor/laravel/valet/server.php";
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME "/Users/cable8mm/.composer/vendor/laravel/valet/server.php";
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
}
{tip} 기술 소양이란 단어는 수학의 Axios(공리-무조건 옳다고 가정하고, 증명하지 않는다.)의 느낌으로, 개발을 진행할 때 개발자가 당연히 알고 있다고 가정하는 기술들을 말합니다. 편의상 직무별로 분류하지는 않습니다.
Composer, NPM 혹은 Cocoapods와 같이 가장 많이 사용하는 패키지매니져를 이용하는 방법과 만드는 방법을 알고 경험을 해 봐야 합니다. Apple과 Microsoft는 공식 패키지매니저를 제공하고 있고, 저장소로 깃헙을 사용합니다. 패키지를 만든 후 패키지매니저 레퍼지토리에 올리는 방법까지 알아야 합니다.
integer 이외의 타입에서 오퍼레이터가 어떻게 작동하는지 알아야 합니다. 특히 오퍼레이터 오버로드를 지원하는 언어들에서는 보통 어떻게 개발되는지 깃헙을 통해서 익혀야 할 필요가 있습니다.
디버깅을 하는 방법은 크게 세가지가 있습니다.
1번 방법이 가장 편하고 가볍게 이용할 수 있습니다. 2번의 경우 headless 개발, 말하자면 화면이 없거나 로직이 복잡할 경우 break point를 이용하기 위해서 사용합니다. 다만, 이벤트를 이용할 경우에는 제대로 된 값이 나오지 않는 경우가 있습니다.
3번은 stream이나 이벤트 코딩을 할 경우 많이 사용하는데요, 로그파일에 tail -f
명령어를 이용해서 화면에 띄워놓고 코딩을 합니다. 로그파일을 중심으로 하기 때문에 리눅스 pipe 커맨드를 과감하게 사용할 수 있어야 원하는 디버깅을 자유롭게 할 수 있습니다.
4번은 CICD가 널리 보급된 후 필수가 되고 있는데요, 현대 언어들은 예외없이 주력 테스트 프레임워크를 지원합니다. 테스트 프레임워크로 만들어진 테스트 코드는 CICD단계에서 매번 실행되기 때문에 매우 편하고 제가 추천하는 방법입니다.
물론 네가지 모두 모국어를 사용하듯이 편하게 사용할 수 있어야 합니다.
프레임워크는 라이프사이클을 이해하는 것이 무엇보다 중요합니다. 이 경우 프레임워크에서 제공하는 테스트 코드가 어떤 원리로 작동되는지 코드레벨에서 이해해야 합니다.
내가 제안하는 구조를 다른 개발자에게 설명하는 방법은 크게 두가지가 있습니다. pseudocode와 다이어그램입니다.
두가지 방법 모두를 이용할 수 있어야 하며, 특히 시퀀스 다이어그램은 툴을 이용해야 하므로 익숙해 지면 질 수록 나의 디자인을 설명하기가 수월해 집니다. 전 markdown 문서와 잘 맞는 mermaid 다이아그램을 이용하고 있습니다.
정규표현식은 언어마다 차이가 거의 없습니다. 즉, 한번 익혀 놓으면 어떤 언어를 사용하던지 문자열 처리를 어렵지 않게 처리할 수 있습니다.
특히 웹을 개발하면 문자열 처리가 중요해 지기 때문에 반드시 익혀야 합니다. 사람은 죽어서 이름을 남기고, 펄 언어는 죽어서 정규표현식을 남겼습니다.
자신의 코드가 배포될 때 까지의 과정이 어떻게 진행되는지 알아야 합니다. 현대 개발은 컴파일 언어 뿐만이 아니라 자바스크립트와 같은 스크립트 언어들도 빌드 후 배포됩니다.
컴파일 언어에 비해 스크립트의 빌드는 훨씬 복잡하며, 문제가 생길 가능성이 높습니다. 따라서, 빌드를 하는 전과정을 이해하지 않으면 빌드할 때 발생하는 문제를 해결하기가 어렵습니다.
Webpack이나 Vite 와 같은 번들링과 빌드를 지원하는 툴의 소스코드를 이해하는 것이 가장 빠른 방법입니다.
깃은 현대 개발에 있어서 이미 가장 중요한 중심이 되고 있습니다. CICD 때문인데요, 따라서 레포지토리를 만들고, 브랜치를 관리하고 PR과 Conflict를 처리할 수 있어야 합니다. 의외로 까다로운데요, 코딩 스타일과 깃헙 액션 등을 과감히 이용하지 않으면 여러명의 개발자들이 동일 레포지토리에서 개발하기가 불가능합니다.
보통 유명한 레포지토리들은 10개 이상의 깃헙액션이 사용되며, 문서와 시스템 전체가 CICD로 자동 배포되고 있습니다. 심지어 여러가지 버전이 동시에 개발될 때에도 깃과 깃헙만으로 운영되고 있을 정도입니다.
마크다운은 문서를 깃으로 만들고 운영하기에 최고의 문서 포멧이며, 별도의 프로그램을 사용하지 않아도 문서를 이해할 수 있을 정도로 매우 단순한 구조입니다. 지금 이 글도 마크다운으로 쓰고 있습니다.
Word나 엑셀을 이용해서 문서를 만들고 있다면 지금부터 마크다운으로 만들어 보세요. 마크다운으로 문서를 만들면 md-to-pdf
패키지 등을 이용해서 커맨드로 pdf로 변환할 수 있습니다. 그리고, 그 문서를 깃헙으로 관리하면 매번 필요한 문서를 제작할 필요가 없어집니다.
컨벤션, 패턴 용어는 별다른 설명 없이 대화할 수 있어야 합니다. 단, 공식 문서에 용어 그대로 사용해야 하며, 편의상 용어를 바꾸지 않습니다.
{tip} 테크닉은 꼭 외우고 있어야 할 필요는 없지만, 공식 문서를 보고 할 수 있어야 합니다.
개발자가 익혀야 하는 기본을 적어봤습니다. 그리고, 의외로 영어 실력이 중요하며, 다른 훌륭한 개발자의 코드를 주기적으로 리뷰하는 것도 도움이 됩니다. 깃헙과 스택오버플로우는 개발에 있어서 너무나도 중요해서 언급할 필요도 없을 정도입니다.
]]>정보 관리 혹은 프로젝트 매니저가 단독으로 운용되기 전 단계 까지라면 이메일 만으로 모든 정보를 유통하는 것이 효율이 좋을 수 있습니다. 본 글에서는 이메일 정보 유통과 소통의 하나의 시나리오를 제안합니다.
단 하나의 룰은 “메신저를 사용하지 않는다” 입니다.
같은 팀에 소속된 매니저님들은 예외없이 이메일로 요청을 하고, 이메일로 회신을 합니다. 물론 내용 파악이 필요할 때에는 전화나 카톡, 미팅을 할 수도 있지만, 그렇다고 하더라도 그 결과를 다시 이메일에 반영을 하죠.
조금 더 자세히 Case Study를 살펴보도록 합니다.
조건 | 처리 방법 |
---|---|
1시간 이내 처리가 가능 | 처리 후 완료 회신. |
1시간 이내 처리가 불가능 | (1) 완료 예정일을 이메일로 알림 (2) 처리 후 완료 회신. |
실제 처리자에게 요청 자체를 넘겨서 처리자가 직접 요청자에게 처리 결과를 Case 1 형식으로 회신하도록 합니다.
만약 요청자의 컨텍포인트가 별도로 정해져 있어서 처리자가 직접 요청자에게 결과를 알릴 수 없는 상황이라면 아래와 같이 Case 1을 중계합니다.
조건 | 처리 방법 |
---|---|
실제 처리자가 1시간 이내 처리가 가능 | 처리 후 완료 회신. |
실제 처리자가 1시간 이내 처리가 불가능 | (1) 완료 예정일을 이메일로 알림 (2) 처리 후 완료 회신. |
다른 팀이라도 이메일로 요청을 받는 것이 기본입니다. 하지만, 부득이하게 그렇지 않을 경우는 아래와 같이 Case 3으로 처리합니다.
조건 | 처리 방법 |
---|---|
카톡, 전화(구두)로 요청 옴 | (1) 일단 내용을 정리해서 요청자에게 이메일을 발송. (2) Case 1, Case 2 방식으로 처리. |
구두로 급하게 요청하는데 30분 안에 처리 가능 | (1) 요청자와 같은 공간에 있으므로, 처리를 그 자리에서 완료합니다. (2) 처리 결과를 메일로 작성해서 요청자에게 발송. |
구두로 급하게 요청하는데 30분 안에 처리 불가능 | (1) 요청 내용을 이메일로 보내달라고 요청 (2) Case 1, Case 2 형식으로 처리합니다. |
새로운 협업 방식을 도입할 때에는 베스트 상황만을 고려하지 않고, 협업 중간에 안 좋은 상황이 발생할 때 어떻게 해야 되는지가 정의되어야 합니다.
]]>비단 개발자 뿐만이 아니라 각종 프로젝트 문서나 심지어 소설, 그림도 깃으로 관리하는 프로젝트가 생기고 있습니다. 마이크로소프트 오피스와 마찬가지로 협업을 하는 사람이라면 점점 깃에 익숙해 져야 할 필요가 있습니다.
따라서, 몇 명이 개발을 하던 소기업이던 대기업이던 Git을 이용하고 Github을 이용해서 협업을 하는 경우가 빠르게 늘고 있습니다. Github의 주인인 마이크로 소프트는 자사의 오픈소스 에디터인 VSCode에서 공식 확장을 이용해서 Github과의 협업을 하나의 툴로 만들어서 제공하고 있습니다.
워낙 자주 사용하는 툴이기 때문에 Git과 Github 을 통해 어떻게 개발을 하는게 베스트인지를 생각 해 봅니다.
오픈소스 프로젝트의 경우 운용상의 이유로 Commit을 이용한 저장소 코드 올리기는 허용하지 않는 경우가 많습니다. 대신, PR을 만들면 각종 테스트와 리뷰, 테스트가 이루어 지고 리뷰어가 승인을 할 경우 main 브랜치에 머지 됩니다.
개발자 입장에서는 PR을 이용한 개발에 두가지 상황이 있을 수 있습니다.
한가지 중요한 점은 현대 개발을 단일 Commit이 작을 수록 관리가 편해지는 경향이 생겼습니다. 그 이유는 CI/CD로 인해 빌드에 대한 모든 것이 자동화 되었기 때문입니다. 과거에는 빌드 매니저가 빌드를 하기까지 몇 주가 걸리는 경우도 있던 시절과는 전혀 다른 양상입니다.
따라서, 이 두가지 상황 모두 하루에도 몇번 씩 발생하고 있습니다. 이 경우 아래 커맨드가 도움을 줄 수 있습니다.
브랜치를 생성하고 이동할 때 아래 세개의 커맨드를 사용합니다.
alias gc="git checkout"
alias gcb="git checkout -b"
alias gb="git branch"
alias gbclean="git branch | grep -v "main" | xargs git branch -D"
hello
라는 브랜치로 예를 들어 보겠습니다.
# hello 브랜치 생성 후 이동
gcb hello
# hello 브랜치 만들기
gb hello
# main 브랜치로 이동
gc main
# PR이 머지된 후 로컬에서 main 브랜치 이외의 모든 브랜치를 삭제
gbclean
전 머지는 Github에서 이루어 지기 때문에 로컬에서는 위 네가지 명령어만으로 개발을 합니다.
PR은 번호가 강조되고 브랜치 이름은 상대적으로 중요하지 않습니다. 따라서, 아래와 같은 명령어를 이용합니다.
#pull request clean
function prc()
{
git for-each-ref refs/heads/pr/ --format='%(refname)' | while read ref ; do branch=${ref#refs/heads/} ; git branch -D $branch ; done
}
#pull request pull
function prp()
{
if [ $# -eq 0 ]; then
echo 'Pull request number need.'
else
git fetch -fu ${2:-origin} refs/pull/$1/head:pr/$1 && git checkout pr/$1
fi
}
#delete branch
function brc()
{
if [ $# -eq 0 ]; then
echo 'Branch name need.'
else
git for-each-ref "refs/heads/**/*$1*" --format='%(refname)' | while read ref ; do branch=${ref#refs/heads/} ; git branch -D $branch ; done
fi
}
이 명령어도 예를 들어 봅니다.
# 3번 PR을 pull
prp 3
# 3번 PR의 브랜치를 삭제
prc 3
# PR 브랜치에서 다시 브랜치를 만들었을 경우 브랜치 이름 매칭이 된 브랜치 전체를 삭제
brc <브랜치 이름 중 일부>
git push
이나 git merge main
과 같은 경우는 별도의 명령어를 만들지 않고 git 명령어 그대로 사용합니다.
다음 번에는 Github에서 제공하는 여러가지 머지 방법에 대해서 이야기 해 보도록 하겠습니다.
]]>Laravel Forge
혹은 Envoyer
입니다.
특히 Envoyer
는 배포할 때 간단한 CI와 원클릭 롤백을 제공해 주며, 프로젝트 중간에 도입할 때 보다 처음에 도입하는 것이 훨씬 간단하기 때문입니다.
제가 처음 Envoyer
를 도입하게 된 계기인 무중단 배포와 롤백이 어떻게 작동하는지 알아보겠습니다.
Envoyer
를 도입하기 전에 해야 할 것은 아래의 명령어입니다.
php artisan storage:link
이 명령어는 storage를 public
폴더의 바깥으로 빼주고, 심볼릭 링크를 걸면서 배포시에 사용자가 업로드한 이미지 등과 소스가 겹치지 않게 해 줍니다.
Envoyer
는 이 링크를 프로젝트의 Root 와 동일한 계층으로 다시 심볼릭 링크를 만듭니다.
실제 서버의 Root 디렉토리:
current -> /home/user/releases/20200511084013/
releases
storage
releases 디렉토리:
20200331041029/
20200331044332/
20200331104152/
...
Envoyer
에서 자동이던 수동이던 배포가 시작되면 releases 디렉토리에 소스를 복사한 후 storage폴더에 심볼릭 링크를 걸고, current의 심볼릭 링크를 교체합니다.
롤백은 배포할 때 에러가 발생하면 자동으로 이루어지며, 관리자 모드에서 원클릭만으로 수동 롤백을 진행할 수 있습니다.
롤백도 배포와 마찬가지입니다. 롤백을 하려는 디렉토리에서 storage폴더에 심볼릭 링크를 걸고, current의 심볼릭 링크를 교체합니다.
그리고…이게 끝입니다! 매우 간단하죠.
무중단 배포에서 중요한 것은 소스 이외의 리소스들이 프로젝트 밖에 있어야 한다는 점입니다.
따라서, 캐시와 세션 폴더를 빼고 심볼릭 링크를 거는 명령어를 배포 스크립트에 추가해 주는 형식으로 어떤 프로젝트도 무중단 배포를 할 수 있습니다.
저흰 Envoyer
를 이용해서 라라벨, CakePHP, Pure PHP 프로젝트 전체를 배포하고 있습니다.
정말 많은 기능이 있습니다만, 제가 실제로 사용하는 기능 위주로 소개해 드립니다.
자동 배포
깃헙과 인증이 연결되어 있으면, 깃헙 후킹으로 배포 엑션이 등록되어 커밋이나 PR이 이루어질 때 자동으로 배포할 수 있습니다.
후킹 스크립트
총 8군데에 후킹 스크립트를 넣을 수 있는 공간을 제공합니다. 저희는 설정 파일 처리를 별도로 작성하여 이용하고 있으며, 라라벨이 아닌 프레임워크의 퍼미션 처리에도 사용합니다.
복수 서버 배포
한 소스를 여러대의 서버에 배포할 수 있습니다. 만약 웹서버 2대에 배치서버 1대를 운영 중이더라도 같은 소스코드를 베이스로 이 기능을 사용하여 배포하는 시나리오를 적용할 수 있게 됩니다.
알림 & 복수 사용자 등록
Slack으로 배포 성공 및 실패 알림을 받을 수 있으며, Envoyer
계정에 복수의 아이디를 만들어서 운영할 수 있습니다.
배포 후 접속 확인(Health Checking)
뉴욕과 런던, 싱가폴에서의 핑 결과를 보여주며, 서버에서도 Envoyer
서버에 정해진 시간마다 핑을 날려서 양측의 Health를 체크해 줍니다. 물론 장애 발생시 Slack이 연결되어 있다면 알람을 보내줍니다.
처음 언급한 CI는 어떻게 하는지 궁금하시다고요?
후킹 스크립트에 composer test
한 줄을 넣으면 에러 발생시 배포가 중단됩니다.
라라벨이 도입한 컴포져와 DI 컨테이너는 에코시스템과의 연동을 더욱 광범위하게 만들어 주고 있습니다.
다른 프레임워크에 비해 라라벨의 최대 강점인데요, 라라벨과 공식적으로 연동되는 에코시스템에도 관심을 갖는다면 더 즐거운 라라벨 생활이 되지 않을까 하네요.
저희가 실제로 배포한 Envoyer
화면을 공유해 드립니다.