<?xml version="1.0" encoding="UTF-8" ?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
	<channel>
		<title>코드 한 줄</title>
		<link>https://blogz-demo.zitt.me/devlog</link>
		<description></description>
		<atom:link href="https://blogz-demo.zitt.me/devlog/rss" rel="self" type="application/rss+xml" />
		<language>ko</language>
		<pubDate>Mon, 28 Sep 2026 05:36:29 +0900</pubDate>
		<generator>Zittme</generator>
			<item>
			<title>3분기 회고: 느리게, 그러나 꾸준히</title>
			<link>https://blogz-demo.zitt.me/devlog/391</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;분기마다 한 번씩 회고를 쓴다. 이번 분기의 주제는 속도였다. 서비스를 빠르게, 그리고 나는 조금 느리게.&lt;/p&gt; &lt;nav data-bz=&quot;toc&quot;&gt;&lt;/nav&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;한 일&lt;/h2&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;목표&lt;/th&gt;&lt;th&gt;결과&lt;/th&gt;&lt;th&gt;상태&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;주문 페이지 1초 이내&lt;/td&gt;&lt;td&gt;평균 0.16초&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;달성&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;복원 훈련 분기 1회&lt;/td&gt;&lt;td&gt;1회&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;달성&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;모바일 화면 개편&lt;/td&gt;&lt;td&gt;70%&lt;/td&gt;&lt;td data-bg=&quot;yellow&quot;&gt;진행 중&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;블로그 월 4편&lt;/td&gt;&lt;td&gt;월 3편&lt;/td&gt;&lt;td data-bg=&quot;red&quot;&gt;아쉬움&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;하지 않기로 한 일&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;bullet&quot;&gt;&lt;li&gt;주말 배포. 월요일 아침에 사고를 수습하는 건 이제 그만.&lt;/li&gt;&lt;li&gt;새 프레임워크 도입. 지금 것으로 충분하다.&lt;/li&gt;&lt;li&gt;알림 전부 켜 두기. 정말 중요한 알림만 남겼다.&lt;/li&gt;&lt;/ul&gt; &lt;blockquote data-bz=&quot;quote&quot; data-style=&quot;big&quot;&gt;&lt;p&gt;더 많이 하지 말고, 덜 망가지게.&lt;/p&gt;&lt;cite&gt;이번 분기 책상 메모&lt;/cite&gt;&lt;/blockquote&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;다음 분기&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;check&quot;&gt;&lt;li data-checked=&quot;0&quot;&gt;모바일 화면 개편 마무리&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;접근성 점검 10항목 모두 통과&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;필진 한결 님과 연재 하나 시작&lt;/li&gt;&lt;/ul&gt; &lt;div data-bz=&quot;divider&quot; data-style=&quot;dots&quot;&gt;&lt;hr /&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;읽어 주셔서 고맙습니다. 궁금한 점은 방명록에 남겨 주세요.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>회고</category>	<category>회고</category><category>분기회고</category><category>사이드프로젝트</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/391</guid>
	<comments>https://blogz-demo.zitt.me/devlog/391#comment</comments>			<pubDate>Sat, 26 Sep 2026 17:12:42 +0900</pubDate>
		</item><item>
			<title>좋은 에러 메시지는 무엇을 말해야 할까</title>
			<link>https://blogz-demo.zitt.me/devlog/386</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;&quot;알 수 없는 오류가 발생했습니다.&quot; 이 문장을 볼 때마다 사용자는 무력해진다. 좋은 에러 메시지는 세 가지를 말한다.&lt;/p&gt; &lt;ol data-bz=&quot;list&quot; data-kind=&quot;number&quot;&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;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;나쁜 예&lt;/th&gt;&lt;th&gt;좋은 예&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-bg=&quot;red&quot;&gt;오류가 발생했습니다.&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;사진을 올리지 못했습니다. 파일이 10MB를 넘습니다. 크기를 줄여 다시 올려 주세요.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td data-bg=&quot;red&quot;&gt;잘못된 입력입니다.&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;전화번호는 숫자만 입력해 주세요. 예: 01012345678&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;php&quot;&gt;throw new UserError( &#039;사진을 올리지 못했습니다. 파일이 10MB를 넘습니다.&#039;, hint: &#039;크기를 줄여 다시 올려 주세요.&#039; );&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;개발자에게 필요한 정보(스택, 요청 번호)는 로그에 남기고, 사용자에게는 다음 행동만 알려 주자.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>백엔드</category>	<category>UX라이팅</category><category>에러메시지</category><category>사용성</category>			<dc:creator>한결</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/386</guid>
	<comments>https://blogz-demo.zitt.me/devlog/386#comment</comments>			<pubDate>Mon, 21 Sep 2026 14:48:42 +0900</pubDate>
		</item><item>
			<title>사용자 천 명이 되던 날</title>
			<link>https://blogz-demo.zitt.me/devlog/381</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;가입자 수가 1,000을 넘었다. 대단한 숫자는 아니지만 둘이서 퇴근 후에 만든 서비스로는 꽤 멀리 왔다.&lt;/p&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;지표&lt;/th&gt;&lt;th&gt;석 달 전&lt;/th&gt;&lt;th&gt;지금&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;가입자&lt;/td&gt;&lt;td&gt;312&lt;/td&gt;&lt;td data-bg=&quot;blue&quot;&gt;1,004&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;주간 활성 사용자&lt;/td&gt;&lt;td&gt;88&lt;/td&gt;&lt;td&gt;341&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;월 서버비&lt;/td&gt;&lt;td&gt;1만 8천 원&lt;/td&gt;&lt;td&gt;3만 2천 원&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;받은 문의&lt;/td&gt;&lt;td&gt;14건&lt;/td&gt;&lt;td&gt;96건&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;잘한 것&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;bullet&quot;&gt;&lt;li&gt;문의에는 하루 안에 답했다.&lt;/li&gt;&lt;li&gt;매주 금요일에 바뀐 점을 짧게 공지했다.&lt;/li&gt;&lt;li&gt;기능보다 속도를 먼저 챙겼다.&lt;/li&gt;&lt;/ul&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;아쉬운 것&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;bullet&quot;&gt;&lt;li&gt;모바일 화면을 너무 늦게 다듬었다.&lt;/li&gt;&lt;li&gt;결제 기능을 서두르다 한 달을 버렸다.&lt;/li&gt;&lt;/ul&gt; &lt;blockquote data-bz=&quot;quote&quot; data-style=&quot;big&quot;&gt;&lt;p&gt;천 명 중 한 명이 보낸 긴 메일이, 천이라는 숫자보다 오래 남는다.&lt;/p&gt;&lt;/blockquote&gt; &lt;p data-bz=&quot;text&quot;&gt;다음 목표는 숫자가 아니라 속도다. 모든 페이지를 0.3초 안에.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>회고</category>	<category>회고</category><category>사이드프로젝트</category><category>사용자</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/381</guid>
	<comments>https://blogz-demo.zitt.me/devlog/381#comment</comments>			<pubDate>Thu, 17 Sep 2026 17:12:42 +0900</pubDate>
		</item><item>
			<title>다크 모드, 색만 뒤집으면 끝일까</title>
			<link>https://blogz-demo.zitt.me/devlog/376</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;다크 모드를 처음 만들 때 흰색을 검은색으로, 검은색을 흰색으로 바꾸면 된다고 생각했다. 결과는 눈이 아픈 화면이었다. 순수한 검정 위의 순수한 흰 글자는 대비가 너무 세다.&lt;/p&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;색은 변수로, 뜻은 이름으로&lt;/h2&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;css&quot;&gt;:root { --bg: #ffffff; --text: #1a1d23; --muted: #69717e; --line: #e8eaee; } @media (prefers-color-scheme: dark) { :root { --bg: #15171c; --text: #e6e8ec; --muted: #9aa2ae; --line: #2a2e36; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;놓치기 쉬운 것&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;check&quot;&gt;&lt;li data-checked=&quot;1&quot;&gt;버튼 호버 색도 다크용으로 따로&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;그림자는 다크에서 거의 안 보인다. 테두리로 대신&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;흰 배경 로고 이미지&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;사용자가 고른 모드를 기억하기&lt;/li&gt;&lt;/ul&gt; &lt;div data-bz=&quot;callout&quot; data-tone=&quot;note&quot;&gt;&lt;p&gt;&lt;code&gt;color-scheme: light dark;&lt;/code&gt; 를 선언하면 스크롤바와 입력칸도 알맞은 색으로 바뀝니다.&lt;/p&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;결국 다크 모드는 색을 뒤집는 일이 아니라, 색마다 역할을 정해 두는 일이었다.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>프런트엔드</category>	<category>CSS</category><category>다크모드</category><category>디자인시스템</category>			<dc:creator>한결</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/376</guid>
	<comments>https://blogz-demo.zitt.me/devlog/376#comment</comments>			<pubDate>Wed, 09 Sep 2026 19:36:42 +0900</pubDate>
		</item><item>
			<title>Nginx 설정 몇 줄로 첫 화면을 빠르게</title>
			<link>https://blogz-demo.zitt.me/devlog/370</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;서버 코드만 빨라서는 부족하다. 정적 파일이 느리면 첫 화면이 늦게 뜬다. Nginx 설정에서 효과가 컸던 것만 모았다.&lt;/p&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;nginx&quot;&gt;gzip on; gzip_types text/css application/javascript image/svg+xml application/json; location ~* \.(css|js|woff2|jpg|png|webp)$ { expires 30d; add_header Cache-Control &quot;public, immutable&quot;; } listen 443 ssl http2;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;지표&lt;/th&gt;&lt;th&gt;전&lt;/th&gt;&lt;th&gt;후&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;첫 화면 표시&lt;/td&gt;&lt;td&gt;2.4초&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;1.1초&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;전송량&lt;/td&gt;&lt;td&gt;1.8MB&lt;/td&gt;&lt;td&gt;640KB&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;div data-bz=&quot;callout&quot; data-tone=&quot;warn&quot;&gt;&lt;p&gt;파일 이름에 버전이나 해시를 붙이지 않고 immutable 캐시를 걸면, 배포 뒤에도 옛 파일이 보입니다.&lt;/p&gt;&lt;/div&gt;</description>
		<category>코드 한 줄</category>	<category>운영 · 인프라</category>	<category>Nginx</category><category>웹성능</category><category>gzip</category><category>캐시</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/370</guid>
	<comments>https://blogz-demo.zitt.me/devlog/370#comment</comments>			<pubDate>Sat, 05 Sep 2026 22:00:42 +0900</pubDate>
		</item><item>
			<title>출시 전에 보는 접근성 체크리스트</title>
			<link>https://blogz-demo.zitt.me/devlog/365</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;접근성은 특별한 사람을 위한 기능이 아니다. 팔을 다친 사람, 햇빛 아래에서 휴대폰을 보는 사람, 모두가 언젠가는 쓴다. 출시 전에 보는 목록을 공유한다.&lt;/p&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;check&quot;&gt;&lt;li data-checked=&quot;1&quot;&gt;모든 이미지에 알맞은 대체 텍스트&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;키보드만으로 모든 기능 사용 가능&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;초점 표시가 보인다&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;글자와 배경 대비 4.5:1 이상&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;버튼과 링크의 이름이 뜻을 말한다&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;입력칸마다 label 연결&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;오류 메시지가 색에만 의존하지 않는다&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;확대 200%에서 가로 스크롤 없음&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;동영상 자막&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;화면 낭독기로 한 번 훑어보기&lt;/li&gt;&lt;/ul&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;용도&lt;/th&gt;&lt;/tr&gt;&lt;tr&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;/tr&gt;&lt;tr&gt;&lt;td&gt;키보드&lt;/td&gt;&lt;td&gt;Tab, Shift+Tab, Enter, Esc 만으로 써 보기&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;blockquote data-bz=&quot;quote&quot; data-style=&quot;line&quot;&gt;&lt;p&gt;접근성 점검의 절반은 마우스를 치우는 것으로 끝난다.&lt;/p&gt;&lt;/blockquote&gt;</description>
		<category>코드 한 줄</category>	<category>프런트엔드</category>	<category>접근성</category><category>웹표준</category><category>체크리스트</category>			<dc:creator>한결</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/365</guid>
	<comments>https://blogz-demo.zitt.me/devlog/365#comment</comments>			<pubDate>Mon, 31 Aug 2026 12:24:42 +0900</pubDate>
		</item><item>
			<title>OPcache 설정, 기본값으로 두지 마세요</title>
			<link>https://blogz-demo.zitt.me/devlog/360</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;쿼리를 고치고 나니 이번에는 PHP 자체가 보였다. 서버에 OPcache가 켜져 있긴 했지만 기본값 그대로였다. 파일 수가 많은 프레임워크에서는 기본 메모리가 금방 찬다.&lt;/p&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;ini&quot;&gt;opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=32 opcache.max_accelerated_files=20000 opcache.validate_timestamps=1 opcache.revalidate_freq=60&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;확인하는 법&lt;/h2&gt; &lt;ol data-bz=&quot;list&quot; data-kind=&quot;number&quot;&gt;&lt;li&gt;&lt;code&gt;opcache_get_status()&lt;/code&gt; 로 캐시 적중률과 남은 메모리를 본다.&lt;/li&gt;&lt;li&gt;적중률이 99% 아래라면 메모리나 파일 수 한도를 늘린다.&lt;/li&gt;&lt;li&gt;배포 직후에는 FPM을 다시 불러와 캐시를 비운다.&lt;/li&gt;&lt;/ol&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;항목&lt;/th&gt;&lt;th&gt;기본값&lt;/th&gt;&lt;th&gt;바꾼 값&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;memory_consumption&lt;/td&gt;&lt;td&gt;128&lt;/td&gt;&lt;td&gt;256&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;max_accelerated_files&lt;/td&gt;&lt;td&gt;10000&lt;/td&gt;&lt;td&gt;20000&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;캐시 적중률&lt;/td&gt;&lt;td&gt;96.2%&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;99.8%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;p data-bz=&quot;text&quot;&gt;응답 시간 평균이 210ms에서 160ms로 더 내려갔다. 코드 한 줄 안 건드리고 얻은 25%.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>운영 · 인프라</category>	<category>PHP</category><category>OPcache</category><category>서버설정</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/360</guid>
	<comments>https://blogz-demo.zitt.me/devlog/360#comment</comments>			<pubDate>Thu, 27 Aug 2026 14:48:42 +0900</pubDate>
		</item><item>
			<title>백업은 복원해 봐야 백업이다</title>
			<link>https://blogz-demo.zitt.me/devlog/354</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;매일 밤 백업이 돌고 있었다. 그런데 한 번도 복원해 본 적이 없었다. 불안해서 주말에 새 서버를 하나 빌려 복원 훈련을 했다. 결과는 반쯤 실패였다.&lt;/p&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;발견한 문제&lt;/h2&gt; &lt;ol data-bz=&quot;list&quot; data-kind=&quot;number&quot;&gt;&lt;li&gt;DB 덤프에 트리거가 빠져 있었다.&lt;/li&gt;&lt;li&gt;첨부 파일 백업이 권한 문제로 절반만 복사되고 있었다.&lt;/li&gt;&lt;li&gt;복원 절차를 아는 사람이 나 하나뿐이었다.&lt;/li&gt;&lt;/ol&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;# 고친 백업 명령 mysqldump --single-transaction --routines --triggers mydb | gzip &amp;gt; db-$(date +%F).sql.gz tar --exclude=&#039;files/cache&#039; -czf files-$(date +%F).tar.gz files&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;div data-bz=&quot;callout&quot; data-tone=&quot;info&quot;&gt;&lt;p&gt;석 달에 한 번, 다른 서버에 실제로 복원해 보는 일정을 달력에 넣어 두었습니다.&lt;/p&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;복원 훈련을 한 뒤로 새벽 알림이 와도 덜 무섭다. 최악의 경우에도 어디까지 되돌릴 수 있는지 알기 때문이다.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>운영 · 인프라</category>	<category>백업</category><category>복원</category><category>운영</category><category>데이터베이스</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/354</guid>
	<comments>https://blogz-demo.zitt.me/devlog/354#comment</comments>			<pubDate>Sat, 22 Aug 2026 17:12:42 +0900</pubDate>
		</item><item>
			<title>커밋 메시지, 미래의 나에게 쓰는 편지</title>
			<link>https://blogz-demo.zitt.me/devlog/349</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;&quot;수정&quot;, &quot;버그 고침&quot;, &quot;ㅇㅇ&quot;. 석 달 전 내가 남긴 커밋 메시지다. 왜 고쳤는지 알 수 없어서 같은 버그를 두 번 고쳤다.&lt;/p&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;지키기로 한 규칙&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;bullet&quot;&gt;&lt;li&gt;첫 줄은 무엇을 바꿨는지 50자 안쪽으로&lt;/li&gt;&lt;li&gt;본문에는 왜 바꿨는지&lt;/li&gt;&lt;li&gt;관련 이슈 번호는 끝에&lt;/li&gt;&lt;/ul&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;주문 목록 N+1 쿼리를 IN 조회로 바꿈 주문 200개 기준 쿼리가 201회에서 2회로 줄어 평균 응답이 1.8초에서 0.2초가 됨. 문의 #128&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;blockquote data-bz=&quot;quote&quot; data-style=&quot;line&quot;&gt;&lt;p&gt;코드는 무엇을 하는지 말하고, 커밋은 왜 했는지 말한다.&lt;/p&gt;&lt;/blockquote&gt;</description>
		<category>코드 한 줄</category>	<category>백엔드</category>	<category>Git</category><category>커밋메시지</category><category>협업</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/349</guid>
	<comments>https://blogz-demo.zitt.me/devlog/349#comment</comments>			<pubDate>Tue, 18 Aug 2026 19:36:42 +0900</pubDate>
		</item><item>
			<title>N+1 쿼리를 한 번에 잡기</title>
			<link>https://blogz-demo.zitt.me/devlog/343</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;지난 편에서 찾은 범인은 이런 코드였다. 주문 목록을 가져온 뒤, 주문마다 상품을 다시 조회한다.&lt;/p&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;php&quot;&gt;foreach ($orders as $order) { // 주문마다 쿼리 한 번씩: 주문 200개면 쿼리 200번 $order-&amp;gt;items = $db-&amp;gt;query(&#039;SELECT * FROM order_items WHERE order_id = ?&#039;, [$order-&amp;gt;id])-&amp;gt;fetchAll(); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;IN 으로 한 번에 가져오기&lt;/h2&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;php&quot;&gt;$ids = array_column($orders, &#039;id&#039;); $marks = implode(&#039;,&#039;, array_fill(0, count($ids), &#039;?&#039;)); $rows = $db-&amp;gt;query(&quot;SELECT * FROM order_items WHERE order_id IN ($marks)&quot;, $ids)-&amp;gt;fetchAll(); $byOrder = []; foreach ($rows as $row) { $byOrder[$row-&amp;gt;order_id][] = $row; } foreach ($orders as $order) { $order-&amp;gt;items = $byOrder[$order-&amp;gt;id] ?? []; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;결과&lt;/h2&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;고치기 전&lt;/th&gt;&lt;th&gt;고친 뒤&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;쿼리 수 (주문 200개)&lt;/td&gt;&lt;td&gt;201회&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;2회&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;평균 응답&lt;/td&gt;&lt;td&gt;1,840ms&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;210ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;최대 응답&lt;/td&gt;&lt;td&gt;5,210ms&lt;/td&gt;&lt;td data-bg=&quot;green&quot;&gt;380ms&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;div data-bz=&quot;callout&quot; data-tone=&quot;warn&quot;&gt;&lt;p&gt;IN 목록이 수천 개가 넘으면 오히려 느려질 수 있습니다. 페이지 단위로 나눠 가져오세요.&lt;/p&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;코드 열 줄 남짓 바꿨을 뿐인데 체감이 완전히 달라졌다. 메일을 보내 준 사용자에게 답장을 쓰면서 가장 뿌듯했던 순간.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>백엔드</category>	<category>PHP</category><category>SQL</category><category>N+1</category><category>성능</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/343</guid>
	<comments>https://blogz-demo.zitt.me/devlog/343#comment</comments>			<pubDate>Fri, 14 Aug 2026 22:00:42 +0900</pubDate>
		</item><item>
			<title>키보드를 바꿨더니 코드가 달라졌다</title>
			<link>https://blogz-demo.zitt.me/devlog/338</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;오 년 쓴 노트북 키보드를 떠나 기계식 키보드를 샀다. 타건감이 좋으니 코드도 잘 써질 거라는 기대가 있었다.&lt;/p&gt; &lt;figure data-bz=&quot;image&quot; data-size=&quot;normal&quot;&gt;&lt;img src=&quot;https://blogz-demo.zitt.me/files/demo/keyboard-12.jpg&quot; alt=&quot;나무 책상 위의 새 키보드&quot; /&gt;&lt;figcaption&gt;나무 책상 위의 새 키보드&lt;/figcaption&gt;&lt;/figure&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;항목&lt;/th&gt;&lt;th&gt;느낌&lt;/th&gt;&lt;/tr&gt;&lt;tr&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;/tr&gt;&lt;tr&gt;&lt;td&gt;생산성&lt;/td&gt;&lt;td&gt;변화 없음. 당연하다&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;p data-bz=&quot;text&quot;&gt;결론은 이렇다. 장비는 기분을 바꾸고, 기분은 앉아 있는 시간을 늘린다. 그 정도면 충분히 좋은 투자다.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>회고</category>	<category>키보드</category><category>작업환경</category><category>장비</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/338</guid>
	<comments>https://blogz-demo.zitt.me/devlog/338#comment</comments>			<pubDate>Fri, 07 Aug 2026 00:24:42 +0900</pubDate>
		</item><item>
			<title>느린 페이지는 어디서 느린가</title>
			<link>https://blogz-demo.zitt.me/devlog/331</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;사용자 한 분이 &quot;주문 내역 페이지가 가끔 5초씩 걸려요&quot;라는 메일을 보냈다. 로컬에서는 0.3초. 이런 문제는 대개 추측으로 고치려다 시간을 버린다. 이번에는 재는 것부터 시작했다.&lt;/p&gt; &lt;nav data-bz=&quot;toc&quot;&gt;&lt;/nav&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;1. 느린 요청부터 모은다&lt;/h2&gt; &lt;p data-bz=&quot;text&quot;&gt;PHP-FPM의 슬로우 로그를 켜면 일정 시간 넘게 걸린 요청의 호출 스택을 남겨 준다. 설정은 두 줄이면 된다.&lt;/p&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;ini&quot;&gt;; /etc/php/8.1/fpm/pool.d/www.conf request_slowlog_timeout = 2s slowlog = /var/log/php-fpm/slow.log&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;하루 동안 모아 보니 느린 요청의 90%가 같은 함수에서 멈춰 있었다. 주문 목록을 돌면서 상품 정보를 하나씩 가져오는 곳이다.&lt;/p&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;2. 숫자로 확인한다&lt;/h2&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;측정 지점&lt;/th&gt;&lt;th&gt;평균&lt;/th&gt;&lt;th&gt;최대&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;전체 요청&lt;/td&gt;&lt;td&gt;1,840ms&lt;/td&gt;&lt;td data-bg=&quot;red&quot;&gt;5,210ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DB 쿼리 합계&lt;/td&gt;&lt;td&gt;1,520ms&lt;/td&gt;&lt;td&gt;4,800ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;템플릿 렌더링&lt;/td&gt;&lt;td&gt;95ms&lt;/td&gt;&lt;td&gt;160ms&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;나머지&lt;/td&gt;&lt;td&gt;225ms&lt;/td&gt;&lt;td&gt;250ms&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;div data-bz=&quot;callout&quot; data-tone=&quot;note&quot;&gt;&lt;p&gt;평균만 보면 안 됩니다. 사용자가 느끼는 건 최댓값과 상위 5%입니다.&lt;/p&gt;&lt;/div&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;3. 범인은 반복문 속 쿼리&lt;/h2&gt; &lt;p data-bz=&quot;text&quot;&gt;주문이 많은 사용자일수록 느렸다. 전형적인 N+1 문제다. 다음 편에서 이걸 어떻게 한 번의 쿼리로 줄였는지 적는다.&lt;/p&gt; &lt;blockquote data-bz=&quot;quote&quot; data-style=&quot;line&quot;&gt;&lt;p&gt;측정하지 않은 최적화는 기도와 같다.&lt;/p&gt;&lt;cite&gt;어느 개발자의 책상 메모&lt;/cite&gt;&lt;/blockquote&gt;</description>
		<category>코드 한 줄</category>	<category>백엔드</category>	<category>PHP</category><category>성능</category><category>프로파일링</category><category>슬로우로그</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/331</guid>
	<comments>https://blogz-demo.zitt.me/devlog/331#comment</comments>			<pubDate>Fri, 31 Jul 2026 19:36:42 +0900</pubDate>
		</item><item>
			<title>첫 장애의 밤</title>
			<link>https://blogz-demo.zitt.me/devlog/325</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;서비스를 연 지 석 달째 되던 날 새벽 두 시, 모니터링 알림이 울렸다. 사이트가 열리지 않는다. 침대에서 노트북을 열었을 때 손이 떨렸다.&lt;/p&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;타임라인&lt;/h2&gt; &lt;figure data-bz=&quot;table&quot; data-head=&quot;1&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;시각&lt;/th&gt;&lt;th&gt;일&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02:04&lt;/td&gt;&lt;td&gt;응답 없음 알림&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02:09&lt;/td&gt;&lt;td&gt;SSH 접속, 디스크 100% 확인&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02:15&lt;/td&gt;&lt;td&gt;원인: 로그 파일 38GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02:18&lt;/td&gt;&lt;td&gt;오래된 로그 압축 · 정리, 서비스 복구&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;02:40&lt;/td&gt;&lt;td&gt;로그 순환 설정 추가&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt; &lt;div data-bz=&quot;callout&quot; data-tone=&quot;warn&quot;&gt;&lt;p&gt;로그 순환(logrotate)을 설정하지 않은 로그는 언젠가 반드시 디스크를 채웁니다.&lt;/p&gt;&lt;/div&gt; &lt;h2 data-bz=&quot;heading&quot;&gt;배운 것&lt;/h2&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;check&quot;&gt;&lt;li data-checked=&quot;1&quot;&gt;디스크 사용량 80% 알림 추가&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;애플리케이션 로그 순환 설정&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;장애 대응 절차 문서화&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;두 번째 담당자 정하기&lt;/li&gt;&lt;/ul&gt; &lt;blockquote data-bz=&quot;quote&quot; data-style=&quot;line&quot;&gt;&lt;p&gt;장애는 기술 문제이기 전에 준비의 문제였다.&lt;/p&gt;&lt;/blockquote&gt; &lt;p data-bz=&quot;text&quot;&gt;복구 뒤 공지를 올리고 잠들었더니 아침에 사용자 몇 분이 &quot;고생하셨어요&quot;라고 댓글을 달아 주셨다. 작은 서비스의 가장 큰 힘은 이런 사람들이다.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>운영 · 인프라</category>	<category>장애대응</category><category>운영</category><category>회고</category><category>디스크</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/325</guid>
	<comments>https://blogz-demo.zitt.me/devlog/325#comment</comments>			<pubDate>Thu, 23 Jul 2026 22:00:42 +0900</pubDate>
		</item><item>
			<title>새 노트북에 개발 환경을 옮기며 정리한 것</title>
			<link>https://blogz-demo.zitt.me/devlog/320</link>
				<description>&lt;p data-bz=&quot;text&quot;&gt;노트북을 바꾸면서 개발 환경을 옮기는 데 하루가 걸렸다. 다음에는 한 시간 안에 끝내려고 설치 목록과 설정을 저장소 하나에 모았다.&lt;/p&gt; &lt;ul data-bz=&quot;list&quot; data-kind=&quot;check&quot;&gt;&lt;li data-checked=&quot;1&quot;&gt;패키지 목록을 파일 하나로&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;셸 설정 · 별칭 저장소에 보관&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;편집기 설정 동기화&lt;/li&gt;&lt;li data-checked=&quot;1&quot;&gt;SSH 키는 새로 만들고 옛 키 폐기&lt;/li&gt;&lt;li data-checked=&quot;0&quot;&gt;로컬 DB 샘플 데이터 스크립트&lt;/li&gt;&lt;/ul&gt; &lt;div data-bz=&quot;code&quot;&gt;&lt;pre&gt;&lt;code data-lang=&quot;bash&quot;&gt;#!/usr/bin/env bash set -e xargs -a packages.txt sudo apt-get install -y ln -sf &quot;/.bashrc&quot; ~/.bashrc ln -sf &quot;/.gitconfig&quot; ~/.gitconfig echo &#039;준비 끝&#039;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p data-bz=&quot;text&quot;&gt;이 글을 쓰고 나서 동료에게 저장소를 보여 줬더니, 자기 것도 만들겠다며 가져갔다.&lt;/p&gt;</description>
		<category>코드 한 줄</category>	<category>운영 · 인프라</category>	<category>개발환경</category><category>dotfiles</category><category>생산성</category>			<dc:creator>윤서</dc:creator>
			<guid isPermaLink="true">https://blogz-demo.zitt.me/devlog/320</guid>
	<comments>https://blogz-demo.zitt.me/devlog/320#comment</comments>			<pubDate>Tue, 14 Jul 2026 22:00:42 +0900</pubDate>
		</item>	</channel>
</rss>
