<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko-KR"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://skyhanull.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://skyhanull.github.io/" rel="alternate" type="text/html" hreflang="ko-KR" /><updated>2026-07-06T00:49:40+09:00</updated><id>https://skyhanull.github.io/feed.xml</id><title type="html">yoonlog</title><subtitle>기록하고 정리하고 공유하는 개인 블로그</subtitle><author><name>yoon</name></author><entry><title type="html">백엔드 - 스프링의 3요소</title><link href="https://skyhanull.github.io/2026/05/31/spring1/" rel="alternate" type="text/html" title="백엔드 - 스프링의 3요소" /><published>2026-05-31T00:00:00+09:00</published><updated>2026-05-31T00:00:00+09:00</updated><id>https://skyhanull.github.io/2026/05/31/spring1</id><content type="html" xml:base="https://skyhanull.github.io/2026/05/31/spring1/"><![CDATA[<h1 id="스프링의-3요소란">스프링의 3요소란?</h1>

<p>Spring Framework의 주축이 되는 3가지 개념을 말한다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">IoC/DI (제어의 역전 / 의존성 주입)</code></li>
  <li><code class="language-plaintext highlighter-rouge">AOP(Aspect Oriented Programming)</code></li>
  <li><code class="language-plaintext highlighter-rouge">PSA(Portable Service Abstraction</code></li>
</ul>

<p><strong>1-1. IoC — 제어의 역전</strong></p>

<p><strong>핵심</strong> 객체 생성의 주도권이 개발자 → 스프링으로 넘어가는 것</p>

<p>제어의 역전은 다른 객체를 직접 생성하거나 제어하는 것이 아니라 <strong>외부에서 관리하는 객체를 가져와 사용하는 것</strong>을 말한다. 클래스 B 객체를 직접 생성하는 것이 아니므로, 어딘가에서 받아와서 사용하고 있다고 추측해볼 수 있다. 이처럼 제어의 역전을 적용하면 객체를 외부에서 관리하게 되고, 실제로 사용할 때에는 외부에서 제공해주는 객체를 받아오게 된다.</p>

<p>스프링에서는 제어의 역전 개념을 중요한 컨셉으로 삼고 있으며, 여기서 외부(= 객체를 관리하는 주체)를 <strong>“스프링 컨테이너”</strong>라고 한다.</p>

<p>```plain text
// 기존 — 개발자가 직접 new
OrderService order = new OrderService(new FixDiscountPolicy());</p>

<p>// IoC — 선언만 하면 스프링 컨테이너가 알아서 만들어줌
@Service
public class OrderService { … }</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>

핵심: `new`를 개발자가 안 써도 됨. 스프링 컨테이너가 대신 객체를 만들고 관리.


**Q. "제어가 역전된다"는 게 뭔데?**


기존은 개발자 코드가 직접 `new` 해서 객체를 만듦 → 개발자가 주도권.IoC는 `@Service` 달아놓고 기다리면 스프링이 알아서 만들어서 줌 → 스프링이 주도권."누가 만드냐"의 주도권이 바뀐 것 = 역전.


**Q. 결국 코드 어딘가는 고쳐야 하잖아. 기존이랑 뭐가 달라?**


고치는 건 맞음. 근데 **어디를** 고치냐가 다름.기존은 Fix가 OrderService, CartService... 여러 파일에 흩어져 있어서 다 찾아서 고쳐야 함.IoC는 Fix가 AppConfig 딱 한 곳에만 있어서 거기만 고치면 끝.


## **1-2. DI — 의존성 주입**


**핵심** 필요한 객체를 밖에서 파라미터로 넣어주는 것


스프링에서는 객체들을 관리하기 위해 제어의 역전을 사용한다. 그리고 **제어의 역전을 구현하기 위해 사용하는 방법이 DI**다.


의존성 = 없으면 동작 못 하는 관계. OrderService는 DiscountPolicy 없으면 동작 못 함.


```plain text
// 나쁜 방식 — Fix가 안에 박혀있음
class OrderService {
    DiscountPolicy dp = new FixDiscountPolicy(); // 바꾸려면 이 파일 직접 고쳐야 함
}

// DI 방식 — 밖에서 넣어줌
class OrderService {
    DiscountPolicy dp;

    public OrderService(DiscountPolicy dp) {
        this.dp = dp;
    }
}

@Service
@RequiredArgsConstructor
public class OrderService {
    private final DiscountPolicy dp;  // 스프링이 알아서 꽂아줌
}
</code></pre></div></div>

<p>OrderService 코드는 하나도 안 건드리고, 파라미터만 바꾸면 됨.</p>

<p>final + 생성자 주입 조합 권장: 한 번 주입되면 못 바꾸니까 안전하고, 반드시 주입받아야 한다는 걸 강제.</p>

<h2 id="2-psa--서비스-추상화"><strong>2. PSA — 서비스 추상화</strong></h2>

<p><strong>핵심</strong> 기술이 바뀌어도 내 코드는 안 바꿔도 됨</p>

<p>스프링이 제공하는 다양한 기술(JPA, MyBatis, JDBC 등)을 추상화해 개발자가 일관된 방식으로 쓸 수 있게 해줌. 어떤 DB 기술을 사용하든 일관된 방식으로 데이터베이스에 접근하도록 인터페이스를 지원함.</p>

<p>```plain text
// DB 기술이 바뀌어도 코드는 그대로
repository.save(객체);  // JDBC든 JPA든 MyBatis든 똑같이 씀</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>

DIP 원칙을 스프링이 기술(DB, 트랜잭션 등)에 직접 적용한 것. DB 깊이 배우면 더 잘 이해됨.


## **3. AOP — 관점 지향 프로그래밍**


**핵심** 공통 기능(로그, 보안, 트랜잭션)을 따로 빼서 한 곳에서 관리


| **종단 (세로)**        | **횡단 (가로)**          |
| ------------------ | -------------------- |
| 핵심 로직 (주문, 결제, 배송) | 공통 기능 (로그, 보안, 트랜잭션) |
| 각 기능이 독립적으로 흐름     | 모든 기능을 가로로 횡단하며 적용   |


```plain text
// AOP 없으면
public void 주문() { 로그(); 보안(); /* 주문 로직 */ }
public void 결제() { 로그(); 보안(); /* 결제 로직 */ }

// AOP 있으면
@Aspect
public class CommonAspect { 로그(); 보안(); }

public void 주문() { /* 주문 로직만 */ }
public void 결제() { /* 결제 로직만 */ }
</code></pre></div></div>]]></content><author><name>yoon</name></author><category term="개발" /><category term="백" /><summary type="html"><![CDATA[스프링의 3요소란?]]></summary></entry><entry><title type="html">테스트</title><link href="https://skyhanull.github.io/2026/05/25/test12/" rel="alternate" type="text/html" title="테스트" /><published>2026-05-25T00:00:00+09:00</published><updated>2026-05-25T00:00:00+09:00</updated><id>https://skyhanull.github.io/2026/05/25/test12</id><content type="html" xml:base="https://skyhanull.github.io/2026/05/25/test12/"><![CDATA[<p>테스트입니다 확인해주세용요</p>]]></content><author><name>yoon</name></author><category term="일상" /><category term="프론트" /><summary type="html"><![CDATA[dddd]]></summary></entry><entry><title type="html">테스트11111</title><link href="https://skyhanull.github.io/2026/05/25/test123/" rel="alternate" type="text/html" title="테스트11111" /><published>2026-05-25T00:00:00+09:00</published><updated>2026-05-25T00:00:00+09:00</updated><id>https://skyhanull.github.io/2026/05/25/test123</id><content type="html" xml:base="https://skyhanull.github.io/2026/05/25/test123/"><![CDATA[<p>속성테스트</p>]]></content><author><name>yoon</name></author><category term="개발" /><summary type="html"><![CDATA[dddd]]></summary></entry><entry><title type="html">Jekyll 블로그를 만들고 Notion과 연동하기까지</title><link href="https://skyhanull.github.io/2026/05/24/jekyll-blog-setup/" rel="alternate" type="text/html" title="Jekyll 블로그를 만들고 Notion과 연동하기까지" /><published>2026-05-24T19:00:00+09:00</published><updated>2026-05-24T19:00:00+09:00</updated><id>https://skyhanull.github.io/2026/05/24/jekyll-blog-setup</id><content type="html" xml:base="https://skyhanull.github.io/2026/05/24/jekyll-blog-setup/"><![CDATA[<p>블로그를 만들고 싶다는 생각만 하다가, 이번에 로컬 Jekyll부터 Notion 자동 연동까지 한 번에 붙였다. 만들면서 했던 작업들을 순서대로 정리해둔다.</p>

<h2 id="1-jekyll-로컬-환경-세팅">1. Jekyll 로컬 환경 세팅</h2>

<p>먼저 로컬에서 블로그를 띄우는 것부터 시작했다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">rbenv</code> 로 Ruby 3.3.5 설치</li>
  <li><code class="language-plaintext highlighter-rouge">bundle install</code> 로 <code class="language-plaintext highlighter-rouge">github-pages</code> gem 설치</li>
  <li><code class="language-plaintext highlighter-rouge">bundle exec jekyll serve</code> 로 로컬 서버 실행</li>
</ul>

<p>생각보다 Ruby 버전 맞추는 게 제일 귀찮았다. macOS 기본 Ruby(2.6)로는 최신 <code class="language-plaintext highlighter-rouge">github-pages</code> gem이 안 깔려서, <code class="language-plaintext highlighter-rouge">rbenv</code> 로 별도 버전을 따로 잡아줘야 했다.</p>

<p>로컬 실행은 이 명령으로 고정했다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>jekyll serve <span class="nt">--livereload</span> <span class="nt">--force_polling</span>
</code></pre></div></div>

<ul>
  <li><code class="language-plaintext highlighter-rouge">--livereload</code> : 저장하면 브라우저가 자동으로 새로고침</li>
  <li><code class="language-plaintext highlighter-rouge">--force_polling</code> : 폴더 경로에 한글이 있으면 macOS가 파일 변경을 감지 못 하는 이슈가 있어서 폴링으로 강제</li>
</ul>

<h2 id="2-한글-permalink-인코딩-이슈">2. 한글 permalink 인코딩 이슈</h2>

<p>한글 카테고리/permalink를 쓰니 빌드할 때 인코딩 에러가 났다. 쉘 로케일이 <code class="language-plaintext highlighter-rouge">C</code> 라서 그랬고, <code class="language-plaintext highlighter-rouge">~/.zshrc</code> 에 로케일을 잡아주니 해결됐다.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">LANG</span><span class="o">=</span>en_US.UTF-8
<span class="nb">export </span><span class="nv">LC_ALL</span><span class="o">=</span>en_US.UTF-8
</code></pre></div></div>

<h2 id="3-seo--배포-세팅">3. SEO / 배포 세팅</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">jekyll-seo-tag</code>, <code class="language-plaintext highlighter-rouge">jekyll-feed</code>, <code class="language-plaintext highlighter-rouge">jekyll-sitemap</code> 플러그인 추가</li>
  <li><code class="language-plaintext highlighter-rouge">_config.yml</code> 에 GTM 스니펫 자동 삽입 구조 (<code class="language-plaintext highlighter-rouge">gtm_id</code> 값만 넣으면 <code class="language-plaintext highlighter-rouge">&lt;head&gt;</code>/<code class="language-plaintext highlighter-rouge">&lt;body&gt;</code> 에 삽입)</li>
  <li>GitHub Actions(<code class="language-plaintext highlighter-rouge">pages.yml</code>)로 푸시하면 자동 배포되도록 구성</li>
</ul>

<h2 id="4-notion을-cms처럼-쓰기-핵심">4. Notion을 CMS처럼 쓰기 (핵심)</h2>

<p>여기가 이번 작업의 메인이었다. 매번 마크다운 파일을 직접 만드는 게 번거로워서, <strong>Notion 데이터베이스에 글을 쓰면 자동으로 블로그 포스트로 올라오게</strong> 만들었다.</p>

<p>구성은 이렇다.</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">@notionhq/client</code> 로 Notion 데이터베이스를 읽고, <code class="language-plaintext highlighter-rouge">notion-to-md</code> 로 본문을 마크다운으로 변환</li>
  <li><code class="language-plaintext highlighter-rouge">scripts/notion-sync.js</code> 가 각 페이지의 제목·날짜·카테고리·태그 속성을 프론트매터로 만들어 <code class="language-plaintext highlighter-rouge">_posts</code> 에 저장</li>
  <li>GitHub Actions(<code class="language-plaintext highlighter-rouge">notion-sync.yml</code>)가 <strong>30분마다</strong> 실행되어, 변경이 있으면 커밋·푸시하고 Pages 배포까지 트리거</li>
</ul>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s2">"</span><span class="s">*/30</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*"</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
</code></pre></div></div>

<p>동기화 스크립트는 <code class="language-plaintext highlighter-rouge">npm run sync</code> 하나로 돌아간다.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
  </span><span class="nl">"sync"</span><span class="p">:</span><span class="w"> </span><span class="s2">"node scripts/notion-sync.js"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h3 id="삽질-포인트">삽질 포인트</h3>

<p>Notion 속성 이름을 코드에서 정확히 매칭해야 하는데, 대소문자나 공백이 조금만 달라도 값을 못 읽었다. 그래서 속성 이름 매칭을 <strong>대소문자·공백 무시</strong> 방식으로 바꿔서 안정적으로 읽히게 했다.</p>

<h2 id="마무리">마무리</h2>

<p>이제 Notion에 글만 쓰면 30분 안에 블로그에 자동으로 올라온다. 마크다운 파일을 직접 건드릴 일이 거의 없어졌다.</p>

<ul>
  <li>글은 Notion에서 편하게 쓰기</li>
  <li>나머지(변환·커밋·배포)는 자동</li>
  <li>디자인은 천천히 다듬기</li>
</ul>

<p>완벽하지 않아도 일단 굴러가는 파이프라인이 만들어진 게 좋다. 여기서부터 천천히.</p>]]></content><author><name>yoon</name></author><category term="개발" /><category term="jekyll" /><category term="blog" /><category term="github-pages" /><category term="notion" /><category term="setup" /><summary type="html"><![CDATA[로컬 Jekyll 세팅부터 GitHub Pages 배포, Notion 글을 자동으로 포스트로 올리는 것까지의 기록.]]></summary></entry><entry><title type="html">yoonlog를 시작하며</title><link href="https://skyhanull.github.io/2026/04/24/starting-yoonlog/" rel="alternate" type="text/html" title="yoonlog를 시작하며" /><published>2026-04-24T19:10:00+09:00</published><updated>2026-04-24T19:10:00+09:00</updated><id>https://skyhanull.github.io/2026/04/24/starting-yoonlog</id><content type="html" xml:base="https://skyhanull.github.io/2026/04/24/starting-yoonlog/"><![CDATA[<p>yoonlog를 시작했다.</p>

<p>기록을 꾸준히 남길 공간이 필요해서 블로그를 만들었고, 너무 복잡하지 않게 오래 가져갈 수 있는 방식으로 시작해보고 싶었다.</p>

<p>앞으로 이곳에는 일하면서 배운 점, 작업하면서 막혔던 부분, 그리고 나중에 다시 보고 싶은 생각들을 천천히 정리해둘 예정이다.</p>

<p>완벽하게 쓰려고 하기보다, 짧더라도 자주 남기는 쪽으로 가보려고 한다.</p>]]></content><author><name>yoon</name></author><category term="일상" /><category term="start" /><category term="blog" /><category term="yoonlog" /><summary type="html"><![CDATA[yoonlog를 처음 열면서 남기는 첫 기록.]]></summary></entry><entry><title type="html">블로그를 시작합니다</title><link href="https://skyhanull.github.io/2026/04/24/welcome-to-my-blog/" rel="alternate" type="text/html" title="블로그를 시작합니다" /><published>2026-04-24T18:40:00+09:00</published><updated>2026-04-24T18:40:00+09:00</updated><id>https://skyhanull.github.io/2026/04/24/welcome-to-my-blog</id><content type="html" xml:base="https://skyhanull.github.io/2026/04/24/welcome-to-my-blog/"><![CDATA[<p>새 블로그를 열었습니다.</p>

<p>이 블로그에서는 일하면서 배운 점, 만드는 과정, 그리고 정리해두고 싶은 생각들을 천천히 쌓아갈 예정입니다.</p>

<p>첫 세팅은 <code class="language-plaintext highlighter-rouge">GitHub Pages + Jekyll</code> 조합으로 시작했습니다. 가볍고 관리가 쉬워서 개인용 기록 공간으로 잘 맞습니다.</p>]]></content><author><name>yoon</name></author><category term="개발" /><category term="프론트" /><category term="blog" /><category term="jekyll" /><category term="github-pages" /><summary type="html"><![CDATA[GitHub Pages와 Jekyll로 개인 블로그를 연 첫 글입니다.]]></summary></entry></feed>