<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ColdBreWoony</title>
    <link>https://woo-nny.tistory.com/</link>
    <description>Le mot impossible n'est pas fran&amp;ccedil;ais.
(내 사전에 불가능이란 없다)</description>
    <language>ko</language>
    <pubDate>Fri, 22 May 2026 12:36:12 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>woonny</managingEditor>
    <image>
      <title>ColdBreWoony</title>
      <url>https://tistory1.daumcdn.net/tistory/6667206/attach/406b04b55bd54d739c295d0a4527a22d</url>
      <link>https://woo-nny.tistory.com</link>
    </image>
    <item>
      <title>Lombok(롬복) vs Record</title>
      <link>https://woo-nny.tistory.com/entry/Lombok%EB%A1%AC%EB%B3%B5-vs-Record</link>
      <description>&lt;h1&gt;Lombok(롬복) vs Record&lt;/h1&gt;
&lt;h2&gt;개요&lt;/h2&gt;
&lt;p&gt;스프링으로 개발하다 보면 DTO, VO, 응답 객체처럼 단순히 데이터를 담는 클래스를 자주 만들게 된다. 이때 생성자, getter, setter, &lt;code&gt;toString()&lt;/code&gt;, &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt; 같은 반복적인 코드를 줄이기 위해 Lombok을 많이 사용한다. 나 역시 처음에는 &lt;code&gt;@Data&lt;/code&gt;를 거의 습관처럼 붙였고, 서비스 클래스에서는 &lt;code&gt;@RequiredArgsConstructor&lt;/code&gt;를 자주 사용했다. 그러다 Java 16부터 도입된 &lt;code&gt;record&lt;/code&gt;를 알게 되었고, 단순 데이터 전달 객체를 만들 때 더 적합한 선택지가 될 수 있겠다고 느꼈다.&lt;/p&gt;
&lt;h2&gt;본문&lt;/h2&gt;
&lt;h3&gt;보일러플레이트 코드란?&lt;/h3&gt;
&lt;p&gt;보일러플레이트(boilerplate) 코드는 최소한의 변경만으로 여러 곳에서 반복적으로 재사용되는 정형화된 코드를 의미한다. 자바에서는 대표적으로 아래와 같은 코드가 여기에 해당한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;생성자&lt;/li&gt;
&lt;li&gt;getter / setter&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;equals()&lt;/code&gt; / &lt;code&gt;hashCode()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이런 코드들은 직접 작성하면 귀찮고 실수하기 쉬워서, Lombok 같은 라이브러리나 Java의 &lt;code&gt;record&lt;/code&gt; 같은 문법을 활용해 줄이는 경우가 많다.&lt;/p&gt;
&lt;h3&gt;Lombok이란?&lt;/h3&gt;
&lt;p&gt;Lombok은 스프링 개발에서 반복적인 코드를 자동으로 생성해주는 라이브러리다. DTO, VO, Entity, Service 등 다양한 클래스에서 보일러플레이트 코드를 줄일 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p&gt;예를 들어 아래와 같은 어노테이션을 자주 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Data&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;@Data&lt;/code&gt;는 다음 어노테이션을 한 번에 포함한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@Getter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Setter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@RequiredArgsConstructor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@ToString&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@EqualsAndHashCode&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;또한 서비스 클래스에서는 보통 다음처럼 &lt;code&gt;final&lt;/code&gt; 필드 기반 생성자 주입을 위해 &lt;code&gt;@RequiredArgsConstructor&lt;/code&gt;를 많이 사용한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Lombok의 장점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;어노테이션만으로 다양한 메서드를 자동 생성할 수 있다.&lt;/li&gt;
&lt;li&gt;가변 객체, 불변 객체 등 여러 패턴에 유연하게 대응할 수 있다.&lt;/li&gt;
&lt;li&gt;스프링에서 생성자 주입, DTO 작성, 로그 객체 선언 등 활용 범위가 넓다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Lombok의 아쉬운 점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;별도 라이브러리 의존성이 필요하다.&lt;/li&gt;
&lt;li&gt;IDE 설정이나 빌드 환경에 따라 처음 사용하는 사람이 헷갈릴 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Data&lt;/code&gt;를 무분별하게 사용하면 의도치 않게 setter까지 모두 열려서 객체가 너무 쉽게 변경될 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Record란?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;record&lt;/code&gt;는 Java 16에서 정식 도입된 문법으로, 데이터를 담기 위한 클래스를 더 간결하게 표현할 수 있게 해준다. 가장 큰 특징은 &lt;strong&gt;불변성(immutability)을 전제로 한다는 점&lt;/strong&gt;이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public record UserResponse(Long id, String name) {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위처럼 선언하면 컴파일 시 아래 요소들이 자동으로 생성된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모든 필드&lt;/li&gt;
&lt;li&gt;생성자&lt;/li&gt;
&lt;li&gt;getter 역할의 접근자 메서드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;equals()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hashCode()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어 &lt;code&gt;UserResponse&lt;/code&gt;의 값은 아래처럼 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;UserResponse user = new UserResponse(1L, &amp;quot;Kim&amp;quot;);
System.out.println(user.id());
System.out.println(user.name());&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Record의 장점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;모든 필드가 사실상 &lt;code&gt;final&lt;/code&gt;이라 값을 변경할 수 없다.&lt;/li&gt;
&lt;li&gt;추가 라이브러리 없이 자바 문법만으로 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;단순 데이터 전달 객체나 읽기 전용 응답 객체를 만들 때 매우 간결하다.&lt;/li&gt;
&lt;li&gt;불변 객체이기 때문에 멀티스레드 환경에서도 비교적 안전하게 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Record의 한계&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;기본적으로 가변 객체로 만들기 어렵다.&lt;/li&gt;
&lt;li&gt;상속 구조가 필요한 경우에는 제약이 있다.&lt;/li&gt;
&lt;li&gt;JPA Entity처럼 프레임워크 특성상 기본 생성자나 프록시가 필요한 곳에는 적합하지 않을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Lombok과 Record의 차이&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;Lombok&lt;/th&gt;
&lt;th&gt;Record&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Java 최소 버전&lt;/td&gt;
&lt;td&gt;Java 6 이상&lt;/td&gt;
&lt;td&gt;Java 16 이상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;추가 라이브러리 필요&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;어노테이션 명시 필요&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;인스턴스 변수의 가변성&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주 사용 목적&lt;/td&gt;
&lt;td&gt;반복 코드 자동 생성&lt;/td&gt;
&lt;td&gt;간결한 불변 데이터 객체 표현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스프링에서 잘 맞는 용도&lt;/td&gt;
&lt;td&gt;Service, DTO, 다양한 클래스&lt;/td&gt;
&lt;td&gt;Request/Response DTO, 읽기 전용 데이터 객체&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;그래서 무엇을 선택해야 할까?&lt;/h3&gt;
&lt;p&gt;정리해보면 두 가지는 서로 완전히 대체하는 관계라기보다, &lt;strong&gt;용도에 따라 선택하는 도구&lt;/strong&gt;에 가깝다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lombok&lt;/strong&gt;: 다양한 클래스에서 반복 코드를 줄이고 싶을 때 유용하다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Record&lt;/strong&gt;: 단순히 데이터를 전달하고, 변경되지 않아야 하는 DTO를 만들 때 적합하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;개인적으로는 예전처럼 DTO에 무조건 &lt;code&gt;@Data&lt;/code&gt;를 붙이기보다, 먼저 이 객체가 &lt;strong&gt;정말 변경되어야 하는지&lt;/strong&gt;를 생각해보는 편이 더 좋다고 느꼈다. 만약 읽기 전용 응답 객체라면 &lt;code&gt;record&lt;/code&gt;가 더 명확하고, 객체의 의도도 코드에 잘 드러난다. 반대로 setter가 필요하거나 프레임워크 제약이 있는 경우에는 Lombok이 여전히 실용적이다.&lt;/p&gt;
&lt;h3&gt;마무리&lt;/h3&gt;
&lt;p&gt;스프링 개발에서 Lombok은 여전히 매우 강력하고 편리한 도구다. 하지만 Java 버전이 충분하고, 단순 데이터 전달용 객체를 만든다면 &lt;code&gt;record&lt;/code&gt;는 더 간결하고 안전한 선택이 될 수 있다.&lt;/p&gt;
&lt;p&gt;이제는 무조건 &lt;code&gt;@Data&lt;/code&gt;를 붙이기보다,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 객체가 변경 가능한가?&lt;/li&gt;
&lt;li&gt;단순 데이터 전달용인가?&lt;/li&gt;
&lt;li&gt;별도 라이브러리 없이 표현할 수 있는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이런 기준으로 Lombok과 Record를 구분해서 사용하는 것이 더 좋은 습관이라고 생각한다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;참고 자료&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@sj70/Lombok-record&quot;&gt;https://velog.io/@sj70/Lombok-record&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://digitalbourgeois.tistory.com/260&quot;&gt;https://digitalbourgeois.tistory.com/260&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ducktopia.tistory.com/106&quot;&gt;https://ducktopia.tistory.com/106&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Developer/Spring</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/14</guid>
      <comments>https://woo-nny.tistory.com/entry/Lombok%EB%A1%AC%EB%B3%B5-vs-Record#entry14comment</comments>
      <pubDate>Tue, 19 May 2026 08:09:32 +0900</pubDate>
    </item>
    <item>
      <title>OpenClaw 테스트 파일</title>
      <link>https://woo-nny.tistory.com/entry/OpenClaw-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%8C%8C%EC%9D%BC</link>
      <description>&lt;p&gt;&lt;strong&gt;요약:&lt;/strong&gt; 이 글에서는 OpenClaw가 Obsidian 경로에 티스토리 형식의 Markdown 파일을 생성하고 git으로 관리할 수 있는지 간단히 테스트합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 서론&lt;/h2&gt;
&lt;p&gt;이 문서는 OpenClaw가 &lt;code&gt;/obsidian/Personal/Tistory&lt;/code&gt; 경로에 직접 파일을 작성할 수 있는지 확인하기 위해 만든 테스트 글입니다.&lt;/p&gt;
&lt;h2&gt;2. 본문 내용&lt;/h2&gt;
&lt;h3&gt;2.1 확인한 내용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Obsidian 볼트 경로에 접근 가능했습니다.&lt;/li&gt;
&lt;li&gt;Markdown 파일 생성이 정상 동작했습니다.&lt;/li&gt;
&lt;li&gt;Git 저장소 인식 및 push 테스트도 가능해졌습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;[!info] 참고사항&lt;br&gt;이 문서는 실제 발행용 글이 아니라 템플릿 적용 여부를 확인하기 위한 테스트 문서입니다.&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;3. 요약 및 결론&lt;/h2&gt;
&lt;p&gt;OpenClaw는 이제 Obsidian 내 티스토리용 글 초안을 작성하고, 이후 git 작업까지 이어서 처리할 수 있는 상태입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;  참고 링크&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.openclaw.ai&quot;&gt;OpenClaw Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>AI/OpenClaw</category>
      <category>Ai</category>
      <category>openclaw</category>
      <category>post</category>
      <category>test</category>
      <category>Tistory</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/13</guid>
      <comments>https://woo-nny.tistory.com/entry/OpenClaw-%ED%85%8C%EC%8A%A4%ED%8A%B8-%ED%8C%8C%EC%9D%BC#entry13comment</comments>
      <pubDate>Fri, 8 May 2026 08:06:15 +0900</pubDate>
    </item>
    <item>
      <title>Telegram Bot Token 및 사용자 ID 얻기</title>
      <link>https://woo-nny.tistory.com/entry/Telegram-Bot-Token-%EB%B0%8F-%EC%82%AC%EC%9A%A9%EC%9E%90-ID-%EC%96%BB%EA%B8%B0</link>
      <description>&lt;h2&gt;서론&lt;/h2&gt;
&lt;p&gt;헤르메스 에이전트와 텔레그램을 연결하기 위해 텔레그램 봇 토큰과 사용자 ID를 얻는 방법에 대해 정리합니다.&lt;/p&gt;
&lt;h2&gt;텔레그램 Bot Token 얻기&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;텔레그램 다운로드 및 실행:&lt;/strong&gt; 웹 또는 데스크톱 버전을 다운로드하여 실행합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BotFather 찾기:&lt;/strong&gt; 텔레그램 검색창에 &lt;code&gt;Botfather&lt;/code&gt;를 입력하고, 인증 마크가 있는 &lt;code&gt;@BotFather&lt;/code&gt;를 선택하여 대화를 시작합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;새 봇 생성:&lt;/strong&gt; &lt;code&gt;/newbot&lt;/code&gt; 명령어를 입력합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이름 및 사용자 이름 설정:&lt;/strong&gt; 봇의 &lt;code&gt;name&lt;/code&gt; (표시될 이름)과 &lt;code&gt;username&lt;/code&gt; (고유 ID, &lt;code&gt;bot&lt;/code&gt;으로 끝나야 함)을 입력합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;토큰 확인:&lt;/strong&gt; 설정 완료 후, 빨간색으로 표시된 &lt;code&gt;숫자:긴문자&lt;/code&gt; 형태의 문자열이 봇 토큰입니다. 이 토큰은 헤르메스 에이전트 설정 시 사용됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;텔레그램 사용자 ID 얻기&lt;/h2&gt;
&lt;p&gt;헤르메스 에이전트가 허용된 사용자만 메시지를 인식하도록 사용자 ID를 얻어야 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;UserInfoBot 찾기:&lt;/strong&gt; &lt;code&gt;Botfather&lt;/code&gt;와 대화하던 곳으로 돌아가 &lt;code&gt;UserInfoBot&lt;/code&gt;을 검색하고, 인증 마크가 있는 &lt;code&gt;@UserInfoBot&lt;/code&gt;을 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ID 확인:&lt;/strong&gt; &lt;code&gt;@UserInfoBot&lt;/code&gt;과의 대화창에서 &lt;code&gt;/start&lt;/code&gt; 명령어를 입력하면 &lt;code&gt;user&lt;/code&gt; 또는 &lt;code&gt;chat id&lt;/code&gt; 값이 표시됩니다. 이 값이 사용자 ID입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;봇 활성화&lt;/h2&gt;
&lt;p&gt;설정이 완료되면 &lt;code&gt;BotFather&lt;/code&gt;가 제공한 대화창 상단의 링크 (봇의 username으로 되어 있는)를 클릭하여 &lt;code&gt;/start&lt;/code&gt;를 입력하면 해당 봇과 대화를 시작할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;다음 단계&lt;/h2&gt;
&lt;p&gt;추후 헤르메스 에이전트의 나머지 설정과 모델 API 연결이 완료되면 텔레그램을 통해 대화를 주고받을 수 있을 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;참고 자료&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://gabrielkim.tistory.com/entry/Telegram-Bot-Token-%EB%B0%8F-Chat-Id-%EC%96%B4%EB%96%B0%EA%B8%B0&quot;&gt;Telegram Bot Token 및 사용자 ID 얻기 - Gabriel Kim의 Tistory&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web Developer/Etc</category>
      <category>bot</category>
      <category>botfather</category>
      <category>Hermes</category>
      <category>Telegram</category>
      <category>token</category>
      <category>텔레그램</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/12</guid>
      <comments>https://woo-nny.tistory.com/entry/Telegram-Bot-Token-%EB%B0%8F-%EC%82%AC%EC%9A%A9%EC%9E%90-ID-%EC%96%BB%EA%B8%B0#entry12comment</comments>
      <pubDate>Fri, 8 May 2026 08:04:25 +0900</pubDate>
    </item>
    <item>
      <title>[AI]하네스 엔지니어링, 결국 AI를 잘 쓰는 사람의 운영 설계에 가깝다</title>
      <link>https://woo-nny.tistory.com/entry/%ED%95%98%EB%84%A4%EC%8A%A4-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EA%B2%B0%EA%B5%AD-AI%EB%A5%BC-%EC%9E%98-%EC%93%B0%EB%8A%94-%EC%82%AC%EB%9E%8C%EC%9D%98-%EC%9A%B4%EC%98%81-%EC%84%A4%EA%B3%84%EC%97%90-%EA%B0%80%EA%B9%9D%EB%8B%A4</link>
      <description>&lt;p&gt; &lt;strong&gt;요약:&lt;/strong&gt; 이 글에서는 하네스 엔지니어링을 단순한 유행어가 아니라, AI 에이전트를 안전하고 반복 가능하게 쓰기 위한 운영 설계라는 관점에서 정리해본다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;1. 서론&lt;/h2&gt;
&lt;p&gt;요즘 AI 관련 글을 보다 보면 &lt;code&gt;프롬프트 엔지니어링&lt;/code&gt;, &lt;code&gt;컨텍스트 엔지니어링&lt;/code&gt;, 그리고 &lt;code&gt;하네스 엔지니어링&lt;/code&gt;이라는 말이 거의 한 세트처럼 따라다닌다. 나도 최근에 관련 글들을 몇 개 읽다가, 처음에는 &amp;quot;내가 이해한 게 맞나? 결국 AI 활용 가이드라인을 내가 만드는 건가?&amp;quot;라는 생각이 먼저 들었다.&lt;/p&gt;
&lt;h2&gt;2. 본문 내용&lt;/h2&gt;
&lt;h3&gt;2.1 내가 이해한 하네스 엔지니어링&lt;/h3&gt;
&lt;p&gt;하네스(Harness)는 원래 말에 다는 마구를 뜻한다. 강한 힘을 억누르는 게 아니라, &lt;strong&gt;안전하고 원하는 방향으로 이끌기 위한 장치&lt;/strong&gt;라는 뜻에 더 가깝다.&lt;/p&gt;
&lt;p&gt;이걸 AI에 대입하면, 하네스 엔지니어링은 모델 자체를 바꾸는 일이 아니라 모델을 둘러싼 환경을 설계하는 일이다. 즉 다음 같은 것들이 여기에 들어간다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어떤 규칙을 읽힐지&lt;/li&gt;
&lt;li&gt;어떤 도구만 쓰게 할지&lt;/li&gt;
&lt;li&gt;어떤 파일을 진실의 원천으로 둘지&lt;/li&gt;
&lt;li&gt;실수했을 때 어떤 검증과 피드백 루프를 넣을지&lt;/li&gt;
&lt;li&gt;어디까지 자동화하고 어디서 멈추게 할지&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;결국 내가 처음에 생각한&lt;br&gt;&lt;strong&gt;&amp;quot;AI 활용하는데 내가 가이드라인을 만든다?&amp;quot;&lt;/strong&gt;&lt;br&gt;라는 이해가 아주 틀린 건 아니었다. 다만 단순 가이드라인 수준이 아니라, &lt;strong&gt;규칙 + 컨텍스트 + 도구 + 검증 + 운영 방식까지 포함한 외부 프레임워크&lt;/strong&gt;에 가깝다.&lt;/p&gt;
&lt;h3&gt;2.2 왜 프롬프트보다 하네스가 중요하다는 말이 나오는가&lt;/h3&gt;
&lt;p&gt;참고한 글들에서 공통적으로 보인 메시지는 하나였다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이제는 질문 한 줄 잘 쓰는 것만으로는 부족하다&lt;/strong&gt;는 것.&lt;/p&gt;
&lt;p&gt;MadPlay 글에서는 프롬프트, 컨텍스트, 하네스를 이렇게 구분했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;프롬프트 엔지니어링: “무엇을 물어볼까?”&lt;/li&gt;
&lt;li&gt;컨텍스트 엔지니어링: “무엇을 보여줄까?”&lt;/li&gt;
&lt;li&gt;하네스 엔지니어링: “전체 환경을 어떻게 설계할까?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 구분이 좋았던 이유는, AI가 실무에 들어오면 문제의 성격이 달라지기 때문이다. 단순 질답이 아니라 긴 작업, 파일 수정, 도구 사용, 팀 규칙 준수, 반복 검증까지 들어가면 프롬프트보다 바깥 환경이 결과를 더 많이 좌우한다.&lt;/p&gt;
&lt;p&gt;Channel 글도 비슷하게 하네스를 &lt;strong&gt;제어(Control), 감시(Monitoring), 개선(Feedback)&lt;/strong&gt; 구조로 설명했는데, 이 표현도 꽤 직관적이었다. 그냥 모델을 똑똑하게 쓰는 방법이 아니라, &lt;strong&gt;안전하게 운영하는 기반 설계&lt;/strong&gt;라는 점이 분명해진다.&lt;/p&gt;
&lt;h3&gt;2.3 내가 인상 깊게 본 포인트들&lt;/h3&gt;
&lt;p&gt;읽으면서 인상 깊었던 포인트는 몇 가지가 있다.&lt;/p&gt;
&lt;h4&gt;1) 남의 하네스를 그대로 복사해 쓰는 건 한계가 있다&lt;/h4&gt;
&lt;p&gt;긱뉴스 위클리 글에서 특히 공감했던 부분은 이거였다.&lt;/p&gt;
&lt;p&gt;요즘은 agent skills, rules, workflows, 서브에이전트 구성이 엄청 공유된다. 좋은 흐름인 건 맞지만, 그걸 그대로 복사해 쓰는 건 &lt;strong&gt;남의 옷을 그대로 입는 것과 비슷하다&lt;/strong&gt;는 표현이 딱 맞았다.&lt;/p&gt;
&lt;p&gt;도메인이 다르고, 프로젝트 크기가 다르고, 내가 원하는 작업 스타일도 다른데, 남이 잘 맞는다고 해서 나한테도 바로 맞는 건 아니다.&lt;/p&gt;
&lt;p&gt;그래서 중요한 건 “좋아 보이는 걸 다 가져오는 것”이 아니라,&lt;br&gt;&lt;strong&gt;내 서비스와 내 작업 방식에 맞게 줄이고 수정하는 것&lt;/strong&gt;이라는 생각이 들었다.&lt;/p&gt;
&lt;h4&gt;2) Everything Claude Code 같은 건 보편 규칙이 아니라 “좋은 출발점”에 가깝다&lt;/h4&gt;
&lt;p&gt;ECC 관련 글도 흥미로웠다. Agents, Skills, Hooks, Rules를 체계적으로 묶어서 하네스처럼 제공한다는 개념은 매력적이다.&lt;/p&gt;
&lt;p&gt;실제 서비스에 적용하려면 수정이 필요하다.&lt;/p&gt;
&lt;p&gt;예를 들어 ECC의 Java 관련 규칙을 그대로 가져오는 것보다,&lt;br&gt;내 프로젝트에서 진짜 반복되는 패턴 몇 개만 뽑아내는 게 더 실용적일 수 있다.&lt;/p&gt;
&lt;p&gt;즉  “정답”보다 &lt;strong&gt;레퍼런스이자 실험 출발점&lt;/strong&gt;으로 보는 게 맞아 보인다.&lt;/p&gt;
&lt;h4&gt;3) 앞으로는 메타 하네스가 더 중요해질 것 같다&lt;/h4&gt;
&lt;p&gt;읽다 보니 제일 재미있었던 부분은 이 흐름이었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;프롬프트를 잘 쓰는 것에서&lt;/li&gt;
&lt;li&gt;컨텍스트를 잘 구성하는 것으로&lt;/li&gt;
&lt;li&gt;다시 하네스를 잘 설계하는 것으로&lt;/li&gt;
&lt;li&gt;앞으로는 &lt;strong&gt;메타 하네스&lt;/strong&gt;, 즉 “에이전트가 스스로 하네스를 생성하고 최적화하는 단계”까지 확장&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이건 그냥 멋있는 말처럼 보일 수도 있는데, 실제로는 꽤 현실적인 방향 같다.&lt;br&gt;처음에는 사람이 규칙을 쌓고, 그다음엔 에이전트가 반복 실패를 학습해서 규칙 초안을 만들고, 사람은 그걸 승인하고 다듬는 구조가 자연스럽다.&lt;/p&gt;
&lt;p&gt;결국 사람의 역할도 “직접 다 하기”보다 &lt;strong&gt;에이전트가 좋은 환경에서 일하게 만드는 설계자&lt;/strong&gt; 쪽으로 이동하는 느낌이다.&lt;/p&gt;
&lt;h3&gt;2.4 그래서 내 결론은&lt;/h3&gt;
&lt;p&gt;지금 시점에서 내가 내린 결론은 이렇다.&lt;/p&gt;
&lt;p&gt;하네스 엔지니어링은 거창한 개념이라기보다,&lt;br&gt;&lt;strong&gt;AI를 반복 가능하고 안전하게, 그리고 내 서비스에 맞게 쓰기 위한 운영 설계&lt;/strong&gt;다.&lt;/p&gt;
&lt;p&gt;그래서 중요한 건 세 가지 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;남이 만든 걸 무작정 복사하지 말 것&lt;/li&gt;
&lt;li&gt;내 프로젝트에서 자주 반복되는 실패와 패턴을 기준으로 줄여서 설계할 것&lt;/li&gt;
&lt;li&gt;프롬프트 한 줄보다, 파일/규칙/훅/권한/검증 흐름을 더 신경 쓸 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;특히 실제 서비스에 AI를 붙여보면 결국 이 단계로 오게 되는 것 같다.&lt;br&gt;어떤 모델이 더 좋냐보다,&lt;br&gt;&lt;strong&gt;그 모델이 내 환경 안에서 어떻게 움직이게 할 거냐&lt;/strong&gt;가 더 중요해진다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;[!info] 참고사항&lt;br&gt;하네스를 크게 만든다고 무조건 좋은 건 아니다. 규칙이 너무 많아지면 오히려 컨텍스트가 비대해지고 충돌이 생긴다. 내 기준에서는 “최소한의 규칙으로 최대한 안정적으로”가 더 맞는 방향처럼 느껴진다.&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h2&gt;3. 요약 및 결론&lt;/h2&gt;
&lt;p&gt;처음에는 하네스 엔지니어링이 또 하나의 유행어처럼 보였는데, 여러 글을 읽고 나니 생각이 조금 바뀌었다.&lt;/p&gt;
&lt;p&gt;이건 단순히 프롬프트를 잘 쓰는 기술이 아니라,&lt;br&gt;AI 에이전트를 실제 프로젝트와 서비스 안에서 &lt;strong&gt;지속 가능하게 운영하는 방법론&lt;/strong&gt;에 더 가깝다.&lt;/p&gt;
&lt;p&gt;내가 현재 이해한 가장 짧은 정의는 이거다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;하네스 엔지니어링은 AI를 잘 쓰는 기술이 아니라, AI가 잘 일할 수밖에 없게 만드는 환경을 설계하는 일이다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;앞으로는 나도 남이 만든 skill과 rule을 그냥 넣기보다,s&lt;br&gt;내 서비스 기준으로 조금씩 줄이고 바꾸면서 써보게 될 것 같다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;  참고 링크&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://news.hada.io/weekly/202615&quot;&gt;https://news.hada.io/weekly/202615&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://channel.io/ko/blog/articles/what-is-harness-2611ddf1&quot;&gt;https://channel.io/ko/blog/articles/what-is-harness-2611ddf1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://goddaehee.tistory.com/575&quot;&gt;https://goddaehee.tistory.com/575&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://madplay.github.io/post/harness-engineering&quot;&gt;https://madplay.github.io/post/harness-engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gpters.org/nocode/post/harness-engineering-complete-summary-3knw3BTfdPoX5K0&quot;&gt;https://www.gpters.org/nocode/post/harness-engineering-complete-summary-3knw3BTfdPoX5K0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>AI</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/11</guid>
      <comments>https://woo-nny.tistory.com/entry/%ED%95%98%EB%84%A4%EC%8A%A4-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%EA%B2%B0%EA%B5%AD-AI%EB%A5%BC-%EC%9E%98-%EC%93%B0%EB%8A%94-%EC%82%AC%EB%9E%8C%EC%9D%98-%EC%9A%B4%EC%98%81-%EC%84%A4%EA%B3%84%EC%97%90-%EA%B0%80%EA%B9%9D%EB%8B%A4#entry11comment</comments>
      <pubDate>Sat, 18 Apr 2026 10:10:05 +0900</pubDate>
    </item>
    <item>
      <title>[OpenClaw]OpenClaw Gateway 권한 오류(pairing required) 해결 방법</title>
      <link>https://woo-nny.tistory.com/entry/OpenClaw-Gateway-%EA%B6%8C%ED%95%9C-%EC%98%A4%EB%A5%98pairing-required-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요약:&lt;/b&gt; 이 글에서는 OpenClaw 대시보드 접속 시 발생한 &lt;code&gt;pairing required&lt;/code&gt; 오류를 임시 우회 방식과 정상 승인 방식으로 비교하고, Docker 환경에서 실제로 해결한 방법을 정리합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 서론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenClaw를 Docker 환경에서 사용하던 중 대시보드 접속 시 &lt;code&gt;pairing required&lt;/code&gt; 오류가 반복적으로 발생했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 설정을 직접 바꿔서 접속 자체는 가능하게 만들었지만, 그 방식은 보안상 문제가 있다고 판단했습니다. 이후 다른 사용자가 공유한 방법을 참고해 정상적인 기기 승인 절차로 해결했고, 이 글에서는 그 과정을 정리합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 본문 내용&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 처음 시도한 임시 우회 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 아래처럼 설정 파일을 직접 바꿨습니다.&lt;/p&gt;
&lt;pre class=&quot;sml&quot;&gt;&lt;code&gt;sed -i 's/&quot;allowInsecureAuth&quot;: true/&quot;dangerouslyDisableDeviceAuth&quot;: true/g' config.json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 대시보드 접속 자체는 가능해졌습니다. 하지만 이름 그대로 &lt;code&gt;dangerouslyDisableDeviceAuth&lt;/code&gt; 는 기기 인증을 사실상 꺼버리는 옵션에 가깝습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 접속은 쉬워지지만 다음과 같은 문제가 생길 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증되지 않은 기기 접근 위험 증가&lt;/li&gt;
&lt;li&gt;LAN 바인드 환경에서 보안 약화&lt;/li&gt;
&lt;li&gt;추후 외부 공개나 리버스 프록시 사용 시 더 큰 위험 발생 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 방법은 &lt;b&gt;임시 확인용 우회책&lt;/b&gt; 정도로만 보고, 계속 유지하는 것은 추천하지 않습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 실제 해결에 도움이 된 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 내용을 찾다가 아래 Reddit 글을 참고했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/clawdbot/comments/1qsguap/disconnected_1008_pairing_required/?tl=ko&amp;amp;captcha=1&quot;&gt;https://www.reddit.com/r/clawdbot/comments/1qsguap/disconnected_1008_pairing_required/?tl=ko&amp;amp;captcha=1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기서 &lt;code&gt;Weekly-Source-101&lt;/code&gt; 사용자가 공유한 방식은 Docker 환경에서 장치 승인 상태를 직접 확인하고 승인하는 방법이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심 명령은 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;docker compose exec openclaw-gateway node dist/index.js devices list --token &amp;lt;your token&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령을 실행하면 &lt;code&gt;Pending&lt;/code&gt; 상태의 기기가 &lt;code&gt;Request ID&lt;/code&gt;와 함께 표시됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 아래 명령으로 승인합니다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;docker compose exec openclaw-gateway node dist/index.js devices approve &amp;lt;Request ID&amp;gt; --token &amp;lt;your token&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식으로 직접 승인해보니, 이후 대시보드 접속이 정상적으로 동작했습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 왜 이 방법이 더 나았는가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법이 좋은 이유는 단순히 보안 기능을 꺼버리는 게 아니라, &lt;b&gt;원래 의도된 device approval 흐름 안에서 문제를 해결한다는 점&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하면 차이는 이렇습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;dangerouslyDisableDeviceAuth&lt;/code&gt; 사용: 빠르지만 보안상 위험한 우회&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devices list&lt;/code&gt; / &lt;code&gt;devices approve&lt;/code&gt; 사용: 정상 승인 절차로 해결&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 Docker 환경에서는 브라우저나 세션 상태만 봐서는 왜 막히는지 파악이 어려울 수 있는데, 장치 승인 상태를 직접 확인할 수 있다는 점이 도움이 됐습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고사항&lt;br /&gt;위 명령을 사용하려면 Gateway 토큰이 필요합니다. 또한 실제 서비스 이름이 &lt;code&gt;openclaw-gateway&lt;/code&gt; 인지, compose 파일 기준 이름이 다른지도 함께 확인하는 것이 좋습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 요약 및 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenClaw 대시보드 접속 시 &lt;code&gt;pairing required&lt;/code&gt; 오류가 발생한다면, 설정으로 인증을 꺼버리기 전에 &lt;b&gt;장치 승인 상태를 먼저 확인하는 방식&lt;/b&gt;을 추천합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 실제로 해본 기준으로는 아래 순서가 가장 현실적이었습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;임시 우회 설정은 원인 파악용으로만 사용&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devices list&lt;/code&gt; 로 Pending 기기 확인&lt;/li&gt;
&lt;li&gt;&lt;code&gt;devices approve&lt;/code&gt; 로 Request ID 승인&lt;/li&gt;
&lt;li&gt;이후 정상 접속 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, 이번 문제는 단순 접속 오류가 아니라 &lt;b&gt;기기 인증이 완료되지 않은 상태&lt;/b&gt;였고, 장치 승인 명령으로 정상 해결할 수 있었습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  참고 링크&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/clawdbot/comments/1qsguap/disconnected_1008_pairing_required/?tl=ko&amp;amp;captcha=1&quot;&gt;https://www.reddit.com/r/clawdbot/comments/1qsguap/disconnected_1008_pairing_required/?tl=ko&amp;amp;captcha=1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.openclaw.ai&quot;&gt;https://docs.openclaw.ai&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>AI</category>
      <category>docker</category>
      <category>Gateway</category>
      <category>openclaw</category>
      <category>pairing</category>
      <category>TroubleShooting</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/10</guid>
      <comments>https://woo-nny.tistory.com/entry/OpenClaw-Gateway-%EA%B6%8C%ED%95%9C-%EC%98%A4%EB%A5%98pairing-required-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95#entry10comment</comments>
      <pubDate>Wed, 15 Apr 2026 07:46:30 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Spring WebFlux: 비동기 논블로킹 리액티브 웹 개발의 시작</title>
      <link>https://woo-nny.tistory.com/entry/Spring-Spring-WebFlux-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EB%A6%AC%EC%95%A1%ED%8B%B0%EB%B8%8C-%EC%9B%B9-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EC%8B%9C%EC%9E%91</link>
      <description>&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. Spring WebFlux란?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5&quot;&gt;Spring WebFlux&lt;/b&gt;는 Spring Framework 5.0부터 도입된 &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;5&quot;&gt;완전한 비차단(Non-Blocking)&lt;/b&gt; 방식의 리액티브 웹 프레임워크입니다. 적은 수의 스레드로 대량의 동시 접속 요청을 효율적으로 처리하기 위해 설계되었으며, &lt;b data-index-in-node=&quot;133&quot; data-path-to-node=&quot;5&quot;&gt;Netty&lt;/b&gt;, Undertow, Servlet 3.1+ 컨테이너 등 다양한 서버 환경에서 실행됩니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;기존 Spring MVC가 '요청 당 스레드(Thread-per-Request)' 모델을 사용했다면, WebFlux는 **이벤트 루프(Event Loop)**와 &lt;b data-index-in-node=&quot;90&quot; data-path-to-node=&quot;6&quot;&gt;비동기 I/O&lt;/b&gt;를 통해 리소스를 극한으로 효율화합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;핵심 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;Non-Blocking I/O:&lt;/b&gt; I/O 작업(DB 조회, API 호출 등) 시 스레드가 대기하지 않고 다른 작업을 처리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;Reactive Streams &amp;amp; Backpressure:&lt;/b&gt; 데이터 소비자가 처리 가능한 만큼만 데이터를 요청하는 &lt;b data-index-in-node=&quot;63&quot; data-path-to-node=&quot;8,1,0&quot;&gt;역압력(Backpressure)&lt;/b&gt; 메커니즘을 지원하여 시스템의 안정성을 보장합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,2,0&quot;&gt;Netty 기본 탑재:&lt;/b&gt; 비동기 이벤트 기반 네트워크 애플리케이션 프레임워크인 Netty를 기본 서버로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;9&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;2. 핵심 기술: Project Reactor&lt;/h2&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;WebFlux는 내부적으로 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;11&quot;&gt;Project Reactor&lt;/b&gt;라는 리액티브 라이브러리를 기반으로 동작합니다. 여기서 가장 중요한 두 가지 퍼블리셔(Publisher) 타입이 있습니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;  Flux (0 ~ N개의 데이터)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0개, 1개 또는 다수의 데이터를 스트림으로 전달할 때 사용합니다.&lt;/li&gt;
&lt;li&gt;예: 리스트 조회, 실시간 이벤트 스트림&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;  Mono (0 ~ 1개의 데이터)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0개 또는 1개의 데이터 결과를 전달할 때 사용합니다.&lt;/li&gt;
&lt;li&gt;예: 단건 조회, HTTP 응답(성공/실패)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;16,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0&quot;&gt;참고:&lt;/b&gt; WebFlux 개발의 핵심은 이 두 타입을 활용하여 데이터를 가공(map, flatMap)하고 흐름을 제어하는 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-path-to-node=&quot;17&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;3. 두 가지 프로그래밍 모델&lt;/h2&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;WebFlux는 개발자의 취향과 상황에 맞춰 두 가지 방식을 모두 지원합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;1) 어노테이션 기반 (Annotation-based)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;기존 Spring MVC와 거의 동일한 방식입니다. @Controller, @GetMapping 등을 그대로 사용할 수 있어 러닝 커브가 낮습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,0&quot;&gt;장점:&lt;/b&gt; 익숙한 패턴, 기존 코드 마이그레이션 용이&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;2) 함수형 라우팅 및 핸들링 (Functional Endpoints)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;Java 8의 람다(Lambda) 스타일을 활용하여 라우터(Router)와 핸들러(Handler)를 명시적으로 분리합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;장점:&lt;/b&gt; 라우팅 로직이 명확함, 테스트 용이, 높은 커스터마이징 가능성&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;26&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size26&quot;&gt;4. Spring MVC vs Spring WebFlux 비교&lt;/h2&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;전통적인 명령형 프로그래밍(Spring MVC)과 반응형 프로그래밍(Spring WebFlux)의 차이를 한눈에 비교해 보겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;29&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;분류&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;명령형 프로그래밍 (Spring MVC)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;반응형 프로그래밍 (Spring WebFlux)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,0,0&quot;&gt;기본 철학&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,1,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,1,0&quot;&gt;Blocking / Synchronous&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,1,2,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,2,0&quot;&gt;Non-Blocking / Asynchronous&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,2,0,0&quot;&gt;처리 방식&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,2,1,0&quot;&gt;명령어를 순서대로 실행 (절차지향)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,2,2,0&quot;&gt;데이터 스트림을 선언하고 변화에 반응&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,3,0,0&quot;&gt;동시성 모델&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,3,1,0&quot;&gt;Thread per Request (요청당 스레드 할당)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,3,2,0&quot;&gt;Event Loop (적은 스레드로 많은 요청 처리)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,4,0,0&quot;&gt;코드 구성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,4,1,0&quot;&gt;명령형 코드 (Imperative)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,4,2,0&quot;&gt;선언형 코드 (Declarative)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,5,0,0&quot;&gt;주요 용도&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,5,1,0&quot;&gt;전통적인 웹 앱, 복잡한 트랜잭션 처리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,5,2,0&quot;&gt;고성능 게이트웨이, 스트리밍 서비스, 실시간 처리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,6,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,6,0,0&quot;&gt;서버 엔진&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,6,1,0&quot;&gt;주로 Tomcat&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;29,6,2,0&quot;&gt;주로 Netty&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-path-to-node=&quot;30&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언제 WebFlux를 써야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 성능이 빨라지는 것이 아닙니다. 높은 동시성을 요구하거나, 마이크로서비스 아키텍처(MSA) 게이트웨이처럼 I/O가 빈번한 곳에서 빛을 발합니다. 일반적인 CRUD 애플리케이션이라면 Spring MVC가 개발 및 디버깅 측면에서 더 유리할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-path-to-node=&quot;31&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;32&quot; data-ke-size=&quot;size26&quot;&gt;5. 참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;33&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/reference/web/webflux.html&quot;&gt;Spring Framework 공식 문서 (WebFlux)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ms727.tistory.com/39&quot;&gt;티스토리 참고 링크 1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://adjh54.tistory.com/232&quot;&gt;티스토리 참고 링크 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Developer/Spring</category>
      <category>spring</category>
      <category>webflux</category>
      <category>webmvc</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/9</guid>
      <comments>https://woo-nny.tistory.com/entry/Spring-Spring-WebFlux-%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EB%A6%AC%EC%95%A1%ED%8B%B0%EB%B8%8C-%EC%9B%B9-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EC%8B%9C%EC%9E%91#entry9comment</comments>
      <pubDate>Thu, 15 Jan 2026 14:17:50 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] MVC 패턴</title>
      <link>https://woo-nny.tistory.com/entry/Spring-MVC-%ED%8C%A8%ED%84%B4</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;소프트웨어 공학, 특히 웹 개발을 공부하다 보면 가장 먼저 마주치게 되는 디자인 패턴이 바로 &lt;b data-index-in-node=&quot;52&quot; data-path-to-node=&quot;4&quot;&gt;MVC(Model-View-Controller)&lt;/b&gt; 입니다. 단순히 코드를 나누는 것을 넘어, 유지보수와 협업을 위해 필수적인 이 패턴에 대해 정리해 봅니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size26&quot;&gt;1. MVC 패턴이란?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6&quot;&gt;MVC (Model - View - Controller)&lt;/b&gt; 는 애플리케이션의 구성 요소를 세 가지 역할로 구분하여 개발하는 소프트웨어 디자인 패턴입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;이 패턴의 핵심 목적은 &lt;b data-index-in-node=&quot;13&quot; data-path-to-node=&quot;7&quot;&gt;&quot;관심사의 분리(Separation of Concerns)&quot;&lt;/b&gt; 입니다. 사용자가 보는 화면(View)과 데이터 처리 로직(Model)을 서로 분리함으로써, 한쪽을 수정하더라도 다른 쪽에 영향을 최소화하여 유지보수를 쉽게 만듭니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. 핵심 구성 요소 (The 3 Components)&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;  Model (모델)&lt;/h3&gt;
&lt;blockquote data-path-to-node=&quot;10&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;10,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0&quot;&gt;&quot;무엇을(Data &amp;amp; Logic) 할 것인가?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;애플리케이션의 정보(데이터)와 데이터를 처리하는 규칙(비즈니스 로직)을 담당합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;역할:&lt;/b&gt; 데이터베이스 입출력, 상수, 변수, 초기값 설정, 비즈니스 로직 수행.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;특징:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,1,1,0&quot;&gt;View나 Controller에 대해 어떠한 정보도 알고 있으면 안 됩니다.&lt;/b&gt; (독립성)&lt;/li&gt;
&lt;li&gt;변경이 일어나면 변경 통지에 대한 처리 방법을 구현해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt; ️ View (뷰)&lt;/h3&gt;
&lt;blockquote data-path-to-node=&quot;14&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;14,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0&quot;&gt;&quot;화면에 어떻게(UI) 보여줄 것인가?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;사용자에게 보여지는 인터페이스(User Interface)를 담당합니다. 웹이라 치면 HTML/CSS로 만들어진 화면이 여기에 해당합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;역할:&lt;/b&gt; 모델이 처리한 데이터를 시각적으로 표현, 사용자 입력을 받아 컨트롤러로 전달.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;특징:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모델이 가지고 있는 정보를 따로 저장해서는 안 됩니다. (화면에 뿌려주기만 함)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,1,1,0&quot;&gt;모델이나 컨트롤러의 로직을 몰라야 합니다.&lt;/b&gt; (단순 표시)&lt;/li&gt;
&lt;li&gt;변경이 일어나면 변경 통지에 대한 처리 방법을 구현해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;  Controller (컨트롤러)&lt;/h3&gt;
&lt;blockquote data-path-to-node=&quot;18&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;18,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0&quot;&gt;&quot;어떻게(Flow) 처리할 것인가?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;Model과 View 사이를 이어주는 다리(Bridge) 역할을 하며, 메인 로직의 흐름을 제어합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;역할:&lt;/b&gt; 사용자 입력(이벤트) 감지, 유효성 검사, 모델 데이터 업데이트 요청, 뷰 선택 및 데이터 전달.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;특징:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,1,0,0&quot;&gt;Model과 View에 대해 알고 있어야 합니다.&lt;/b&gt; (누구에게 시킬지 알아야 하므로)&lt;/li&gt;
&lt;li&gt;모델이나 뷰의 변경을 모니터링해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;21&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;3. MVC의 동작 과정 (Workflow)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션(예: Spring, Node.js 등)에서의 일반적인 흐름은 다음과 같습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;24&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;**사용자(User)**가 웹사이트에 접속하거나 버튼을 클릭합니다. (&lt;b data-index-in-node=&quot;39&quot; data-path-to-node=&quot;24,0,0&quot;&gt;Request&lt;/b&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,1,0&quot;&gt;Controller&lt;/b&gt;가 이 요청을 받습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,2,0&quot;&gt;Controller&lt;/b&gt;는 요청을 분석하고, 필요한 데이터를 가져오기 위해 &lt;b data-index-in-node=&quot;39&quot; data-path-to-node=&quot;24,2,0&quot;&gt;Model&lt;/b&gt;을 호출합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,3,0&quot;&gt;Model&lt;/b&gt;은 데이터베이스 등에서 데이터를 찾거나 비즈니스 로직을 처리한 후 결과를 반환합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,4,0&quot;&gt;Controller&lt;/b&gt;는 Model로부터 받은 데이터를 가지고, 사용자에게 보여줄 적절한 &lt;b data-index-in-node=&quot;48&quot; data-path-to-node=&quot;24,4,0&quot;&gt;View&lt;/b&gt;를 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,5,0&quot;&gt;View&lt;/b&gt;는 전달받은 데이터를 사용하여 화면을 구성(Rendering)합니다.&lt;/li&gt;
&lt;li&gt;최종적인 화면이 &lt;b data-index-in-node=&quot;9&quot; data-path-to-node=&quot;24,6,0&quot;&gt;사용자&lt;/b&gt;에게 전달됩니다. (&lt;b data-index-in-node=&quot;23&quot; data-path-to-node=&quot;24,6,0&quot;&gt;Response&lt;/b&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-path-to-node=&quot;25&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size26&quot;&gt;4. 왜 MVC를 사용하는가? (장단점)&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;✅ 장점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;28&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,0,0&quot;&gt;유지보수의 용이성:&lt;/b&gt; 디자이너(View)와 개발자(Model, Controller)가 각자의 영역에 집중할 수 있어 협업이 쉽습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,0&quot;&gt;확장성:&lt;/b&gt; 새로운 기능을 추가할 때 다른 컴포넌트에 영향을 덜 줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,2,0&quot;&gt;재사용성:&lt;/b&gt; 하나의 모델을 여러 뷰(PC 버전, 모바일 버전 등)에서 재사용할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;❌ 단점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;30&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,0&quot;&gt;복잡도 증가:&lt;/b&gt; 간단한 기능을 만들 때는 오히려 구조가 복잡해질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,1,0&quot;&gt;학습 곡선:&lt;/b&gt; 초심자에게는 파일이 분리되어 있어 흐름을 파악하기 어려울 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-path-to-node=&quot;31&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;32&quot; data-ke-size=&quot;size26&quot;&gt;5. 지켜야 할 5가지 규칙&lt;/h2&gt;
&lt;p data-path-to-node=&quot;33&quot; data-ke-size=&quot;size16&quot;&gt;MVC 패턴을 제대로 사용하기 위해 다음 규칙들을 염두에 두면 좋습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;34&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,0,0&quot;&gt;Model&lt;/b&gt;은 Controller와 View에 의존하지 않아야 한다. (Model 내부에 Controller/View 코드가 있으면 안 됨)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,1,0&quot;&gt;View&lt;/b&gt;는 Model에만 의존해야 하고, Controller에는 의존하면 안 된다. (데이터를 받기 위해 모델은 알 수 있음)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,2,0&quot;&gt;View&lt;/b&gt;가 Model로부터 데이터를 받을 때는, 사용자마다 다르게 보여주어야 하는 데이터만 받아야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,3,0&quot;&gt;Controller&lt;/b&gt;는 Model과 View에 의존해도 된다. (중재자 역할)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,4,0&quot;&gt;View&lt;/b&gt;가 Model로부터 데이터를 받을 때, 반드시 Controller를 통해 받아야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-path-to-node=&quot;35&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;36&quot; data-ke-size=&quot;size26&quot;&gt;  참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;37&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ittrue.tistory.com/234&quot;&gt;ITTrue - MVC 패턴이란?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Glossary/MVC&quot;&gt;MDN Web Docs - MVC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nahaan.tistory.com/65&quot;&gt;Nahaan - MVC 패턴 이해하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Developer/Spring</category>
      <category>spring</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/8</guid>
      <comments>https://woo-nny.tistory.com/entry/Spring-MVC-%ED%8C%A8%ED%84%B4#entry8comment</comments>
      <pubDate>Wed, 14 Jan 2026 09:44:22 +0900</pubDate>
    </item>
    <item>
      <title>[Spring]ObjectMapper를 매번 호출하면 안 되는 이유</title>
      <link>https://woo-nny.tistory.com/entry/ObjectMapper%EB%A5%BC-%EB%A7%A4%EB%B2%88-%ED%98%B8%EC%B6%9C%ED%95%98%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;초록색 노란색 귀여운 일러스트 블로그 썸네일 인스타그램 포스트-5.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wsTQ6/btsMPqkCfhu/lI9DWEU27Ng1VZa355IFOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wsTQ6/btsMPqkCfhu/lI9DWEU27Ng1VZa355IFOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wsTQ6/btsMPqkCfhu/lI9DWEU27Ng1VZa355IFOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwsTQ6%2FbtsMPqkCfhu%2FlI9DWEU27Ng1VZa355IFOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1080&quot; data-filename=&quot;초록색 노란색 귀여운 일러스트 블로그 썸네일 인스타그램 포스트-5.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ObjectMapper는 Java 객체와 JSON 데이터를 변환하는 데 널리 사용되는 도구입니다. 하지만 매번 새로운 ObjectMapper 인스턴스를 생성하는 것은 여러 가지 문제를 야기할 수 있습니다. 이 글에서는 ObjectMapper를 매번 호출하지 말아야 하는 이유와 더 나은 사용 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ObjectMapper 반복 생성의 문제점&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 저하&lt;/b&gt;: ObjectMapper는 내부적으로 많은 초기화 작업을 수행하기 때문에, 일반 객체에 비해 생성 비용이 높습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일관성 부족&lt;/b&gt;: 매번 새로운 인스턴스를 생성하면 날짜 형식, 직렬화 규칙 등이 매번 초기화되어 일관성이 깨질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지보수 어려움&lt;/b&gt;: 설정이 분산되어 있으면 코드 유지보수가 어려워집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐시 효율성 저하&lt;/b&gt;: ObjectMapper는 내부적으로 캐시를 사용하는데, 매번 새로운 인스턴스를 생성하면 이 캐시가 초기화되어 효율성이 떨어집니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결책: 싱글톤 패턴 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 ObjectMapper를 싱글톤 패턴으로 사용하는 것이 좋습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;싱글톤 패턴이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤 패턴은 객체의 인스턴스가 오직 1개만 생성되는 디자인 패턴입니다. 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이며, 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 반환합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ObjectMapper를 싱글톤으로 사용해야 하는 이유&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;쓰레드 안전성&lt;/b&gt;: ObjectMapper는 쓰레드 안전(Thread-Safe)하므로 싱글톤으로 사용해도 문제가 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 효율성&lt;/b&gt;: 하나의 인스턴스만 유지하므로 메모리 사용을 최적화할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 향상&lt;/b&gt;: 객체 생성 비용을 줄이고, 내부 캐시를 효과적으로 활용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;설정 일관성&lt;/b&gt;: 모든 곳에서 동일한 설정을 사용하므로 일관성을 유지할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Spring에서의 ObjectMapper 싱글톤 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring 프레임워크에서는 @Bean 어노테이션을 사용하여 ObjectMapper를 싱글톤으로 등록하고 사용할 것을 권장합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설정 예시&lt;/h2&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;
@Configuration 
public class JacksonConfig { 

    @Bean 
    public ObjectMapper objectMapper() { 
        ObjectMapper objectMapper = new ObjectMapper(); // 필요 시 커스터마이징 설정 

        objectMapper.registerModule(new JavaTimeModule()); // 날짜 처리 모듈 등록 

        objectMapper.findAndRegisterModules(); // 다른 모듈 자동 등록 (선택) 

        return objectMapper; 
    } 
}  &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 예시&lt;/h2&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;
private final ObjectMapper objectMapper; 

public MyService(ObjectMapper objectMapper) { 
    this.objectMapper = objectMapper; 
}  &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ObjectMapper를 매번 새로 생성하는 대신 싱글톤 패턴을 사용하면 성능 향상, 메모리 효율성, 설정 일관성 등 여러 이점을 얻을 수 있습니다. 특히 Spring 환경에서는 @Bean 등록을 통해 쉽게 싱글톤 ObjectMapper를 사용할 수 있으므로, 이를 적극 활용하는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;##참조&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@seongwon97/%EC%8B%B1%EA%B8%80%ED%86%A4Singleton-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80&quot;&gt;https://velog.io/@seongwon97/%EC%8B%B1%EA%B8%80%ED%86%A4Singleton-%ED%8C%A8%ED%84%B4%EC%9D%B4%EB%9E%80&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2020-11-07-singleton/&quot;&gt;https://tecoble.techcourse.co.kr/post/2020-11-07-singleton/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://border-line.tistory.com/116&quot;&gt;https://border-line.tistory.com/116&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@developerlyk/ObjectMapper-%EB%B9%88-%EB%93%B1%EB%A1%9D%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9&quot;&gt;https://velog.io/@developerlyk/ObjectMapper-%EB%B9%88-%EB%93%B1%EB%A1%9D%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Developer/Spring</category>
      <category>framwork</category>
      <category>Java</category>
      <category>json</category>
      <category>ObjectMapper</category>
      <category>Singleton</category>
      <category>spring</category>
      <category>싱글톤</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/6</guid>
      <comments>https://woo-nny.tistory.com/entry/ObjectMapper%EB%A5%BC-%EB%A7%A4%EB%B2%88-%ED%98%B8%EC%B6%9C%ED%95%98%EB%A9%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0#entry6comment</comments>
      <pubDate>Thu, 6 Mar 2025 19:14:20 +0900</pubDate>
    </item>
    <item>
      <title>[OS]Ubuntu 22.04 Crontab 스크립트 실행 안되는 문제</title>
      <link>https://woo-nny.tistory.com/entry/Ubuntu-2204-Crontab-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%A4%ED%96%89-%EC%95%88%EB%90%98%EB%8A%94-%EB%AC%B8%EC%A0%9C</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;초록색 노란색 귀여운 일러스트 블로그 썸네일 인스타그램 포스트-4.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5cZw6/btsMP9Cf1a2/o1p7vqkzS9wPnTKM1n5TQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5cZw6/btsMP9Cf1a2/o1p7vqkzS9wPnTKM1n5TQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5cZw6/btsMP9Cf1a2/o1p7vqkzS9wPnTKM1n5TQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5cZw6%2FbtsMP9Cf1a2%2Fo1p7vqkzS9wPnTKM1n5TQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1080&quot; data-filename=&quot;초록색 노란색 귀여운 일러스트 블로그 썸네일 인스타그램 포스트-4.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ubuntu 22.04 Crontab 스크립트 정상 작동 안되는 문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 사용하던 CentOS 7에 미들웨어가 정상작동 하지 않아서 OS를 Ubuntu로 변경 하기로 결정 했다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Crontab 사용 했지만 스크립트가 정상 작동 하지 않는 문제가 발생 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/Cron&quot;&gt;Cron&lt;/a&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유닉스 계열 운영체제의 시간 기반 잡 스케줄러이다. 쉽게 설명 하면 특정 시간에 특정 작업을 실행 할 수 있게 만든 프로그램이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;crontab 사용 방법&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt; # ┌───────────── min (0 - 59)
 # │ ┌────────────── hour (0 - 23)
 # │ │ ┌─────────────── day of month (1 - 31)
 # │ │ │ ┌──────────────── month (1 - 12)
 # │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0)
 # │ │ │ │ │
 # │ │ │ │ │
 # * * * * *  command to execute&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시1) &lt;b&gt;0 20 * * * /home/user/scripts/example.sh&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;매일 20시에 example.sh 스크립트를 실행한다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구성 파일은 &lt;i&gt;crontab -e&lt;/i&gt; 로 호출하여 편집한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;첫번째 시도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;별도의 설정을 하지 않는 경우 cron 로그는 /var/log/syslog 확인이 가능하다.&lt;/li&gt;
&lt;li&gt;로그를 확인 한 결과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;(CRON) info (No MTA installed, discarding output)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MTA(메일 전송 관리자)가 설치가 안되서 생긴 오류&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;sudo apt-get install postfix&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;찾아보니 MTA와 별개로 cron은 정상 작동해야 한다는 말이 있었다.&lt;/li&gt;
&lt;li&gt;스크립트가 정상 작동을 하지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;두번쨰 시도(해결)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/etc/crontab을 확인 해보면 &lt;i&gt;SHELL=/bin/sh&lt;/i&gt; 로 되어 있다.&lt;/li&gt;
&lt;li&gt;CentOS 에서는 &lt;i&gt;SHELL=/bin/bash&lt;/i&gt; 되어 있다.&lt;/li&gt;
&lt;li&gt;정상적으로 스크립트가 실행이 안되는것이 shell 문제일 걸로 예상 했다.&lt;/li&gt;
&lt;li&gt;crontab -e 편집 하여 첫번째 줄에 SHELL=/bin/bash 추가 하였다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상 작동 확인&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법 : crontab -e -&amp;gt; SHELL=/bin/bash 추가&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고사이트&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://skyseven73.tistory.com/15&quot;&gt;https://skyseven73.tistory.com/15&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yoshikixdrum.tistory.com/231&quot;&gt;https://yoshikixdrum.tistory.com/231&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Developer/OS</category>
      <category>CentOS</category>
      <category>centos7</category>
      <category>Linux</category>
      <category>OS</category>
      <category>server</category>
      <category>ubuntu</category>
      <category>ubuntu 22.04</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/5</guid>
      <comments>https://woo-nny.tistory.com/entry/Ubuntu-2204-Crontab-%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8B%A4%ED%96%89-%EC%95%88%EB%90%98%EB%8A%94-%EB%AC%B8%EC%A0%9C#entry5comment</comments>
      <pubDate>Thu, 20 Feb 2025 17:46:17 +0900</pubDate>
    </item>
    <item>
      <title>[Etc] SSR vs CSR</title>
      <link>https://woo-nny.tistory.com/entry/%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-SSR-vs-CSR</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;초록색 노란색 귀여운 일러스트 블로그 썸네일 인스타그램 포스트-3.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zQO7r/btsMPmJq5Oq/KVKziXaxpdsH3oLG8u7bPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zQO7r/btsMPmJq5Oq/KVKziXaxpdsH3oLG8u7bPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zQO7r/btsMPmJq5Oq/KVKziXaxpdsH3oLG8u7bPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzQO7r%2FbtsMPmJq5Oq%2FKVKziXaxpdsH3oLG8u7bPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;1080&quot; data-filename=&quot;초록색 노란색 귀여운 일러스트 블로그 썸네일 인스타그램 포스트-3.png&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;title : '[알아보기] SSR vs CSR'&lt;br /&gt;date : 2024-08-19&lt;br /&gt;draft : false&lt;br /&gt;categories:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tags:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CS&lt;/li&gt;
&lt;li&gt;Computer Science&lt;/li&gt;
&lt;li&gt;description:&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SSR(Server Side Rendering)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 사이드 렌더링&lt;/li&gt;
&lt;li&gt;서버 쪽에서 렌더링을 하여 화면을 보여주는 방식&lt;/li&gt;
&lt;li&gt;서버에 매번 데이터 요청하고 서버에서 처리하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;SSR 장점&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫페이지 로딩속도가 빠르다.&lt;/li&gt;
&lt;li&gt;검색엔진 최적화가 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;SSR 단점&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 로딩 이후 페이지 이동 시 속도가 CSR에 비해 느리다.&lt;/li&gt;
&lt;li&gt;서버 과부하&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CSR (Client Side Rendering)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 사이드 렌더링&lt;/li&gt;
&lt;li&gt;서버에서 받은 데이터를 클라이언트인 브라우저가 화면에 그림&lt;/li&gt;
&lt;li&gt;클라이언트인 브라우저가 렌더링을 도맡아 처리하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;CSR 장점&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 로딩 이후 빠른 웹사이트 렌더링이 가능&lt;/li&gt;
&lt;li&gt;트래픽 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;CSR 단점&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;검색엔진 최적화에 보완필요&lt;/li&gt;
&lt;li&gt;초기 로딩 느림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 사이트&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://velog.io/@taek2yo/CSR-%EA%B3%BC-SSR%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&quot;&gt;https://velog.io/@taek2yo/CSR-%EA%B3%BC-SSR%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://f-lab.kr/insight/comparing-ssr-and-csr&quot;&gt;https://f-lab.kr/insight/comparing-ssr-and-csr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EB%B9%84%EA%B0%9C%EB%B0%9C%EC%9E%90-it-%EA%B0%9C%EB%B0%9C-%EC%A7%80%EC%8B%9D&quot;&gt;https://www.inflearn.com/course/%EB%B9%84%EA%B0%9C%EB%B0%9C%EC%9E%90-it-%EA%B0%9C%EB%B0%9C-%EC%A7%80%EC%8B%9D&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web Developer/Etc</category>
      <category>Computer science</category>
      <category>cs</category>
      <author>woonny</author>
      <guid isPermaLink="true">https://woo-nny.tistory.com/4</guid>
      <comments>https://woo-nny.tistory.com/entry/%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-SSR-vs-CSR#entry4comment</comments>
      <pubDate>Thu, 20 Feb 2025 17:43:11 +0900</pubDate>
    </item>
  </channel>
</rss>