<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>큐레이트의 기록</title>
    <link>https://qratedev.tistory.com/</link>
    <description>저의 일상을 기록하는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Wed, 29 Jul 2026 03:34:01 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>큐레이트</managingEditor>
    <image>
      <title>큐레이트의 기록</title>
      <url>https://tistory1.daumcdn.net/tistory/2123023/attach/63f0658500dc4f9dac7d95d61bddd4d4</url>
      <link>https://qratedev.tistory.com</link>
    </image>
    <item>
      <title>[nextjs] npx 설치 오류 해결법</title>
      <link>https://qratedev.tistory.com/202</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;환경: windows 11&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;오류메세지&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npx : 이 시스템에서 스크립트를 실행할 수 없으므로 C:\Program Files\nodejs\npx.ps1 파일을 로드할 수 없습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;해결 방법&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;powershell를 관리자 권한으로 실행후 Set-ExecutionPolicy RemoteSigned 입력후 엔터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경하시겠습니까?는 Y를 입력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brW2V3/dJMcaaKMRXV/0Kyak0DBTeFoDEvP9TgBok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brW2V3/dJMcaaKMRXV/0Kyak0DBTeFoDEvP9TgBok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brW2V3/dJMcaaKMRXV/0Kyak0DBTeFoDEvP9TgBok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrW2V3%2FdJMcaaKMRXV%2F0Kyak0DBTeFoDEvP9TgBok%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;684&quot; height=&quot;358&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/nextjs</category>
      <category>nextjs</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/202</guid>
      <comments>https://qratedev.tistory.com/202#entry202comment</comments>
      <pubDate>Wed, 14 Jan 2026 01:44:00 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 파일 자동 정리 프로그램 만들기 &amp;ndash; 확장자별 분류부터 이동, 삭제까지</title>
      <link>https://qratedev.tistory.com/201</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] 파일 자동 정리 프로그램 만들기 – 확장자별 분류부터 이동, 삭제까지&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다운로드 폴더가 온갖 파일로 가득한가요?&lt;br /&gt;&lt;br /&gt;
파이썬을 활용하면 파일을 &lt;b&gt;확장자 기준으로 자동 정리&lt;/b&gt;하거나, &lt;b&gt;특정 조건에 맞는 파일만 이동/삭제&lt;/b&gt;하는 프로그램을 쉽게 만들 수 있습니다.&lt;br /&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;✅ 1. 기본 파일 정리 로직 – 확장자별로 폴더로 이동&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
import os
import shutil

# 정리할 폴더 경로
target_folder = &quot;C:/Users/사용자/Downloads&quot;

# 이동할 확장자별 폴더 매핑
extension_map = {
    '.jpg': '이미지',
    '.png': '이미지',
    '.pdf': '문서',
    '.xlsx': '엑셀',
    '.zip': '압축',
}

# 파일 정리 실행
for filename in os.listdir(target_folder):
    ext = os.path.splitext(filename)[1].lower()
    folder_name = extension_map.get(ext)
    
    if folder_name:
        dest_folder = os.path.join(target_folder, folder_name)
        os.makedirs(dest_folder, exist_ok=True)
        
        src = os.path.join(target_folder, filename)
        dst = os.path.join(dest_folder, filename)
        shutil.move(src, dst)
&lt;/code&gt;&lt;/pre&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;✅ 2. 특정 패턴/날짜 기준으로 삭제하기&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
import time

now = time.time()
days = 30  # 30일 이상 지난 파일만 삭제

for filename in os.listdir(target_folder):
    file_path = os.path.join(target_folder, filename)
    if os.path.isfile(file_path):
        last_modified = os.path.getmtime(file_path)
        if now - last_modified &gt; days * 86400:
            os.remove(file_path)
&lt;/code&gt;&lt;/pre&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;✅ 3. 숨김파일, 특정 키워드 포함 파일 예외 처리&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
# 숨김 파일(.으로 시작) 또는 특정 키워드가 포함된 파일은 무시
skip_keywords = ['keep', 'README']

for filename in os.listdir(target_folder):
    if filename.startswith('.') or any(k in filename for k in skip_keywords):
        continue
    # 나머지는 정리 로직으로 진행
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;

&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 더 이상 다운로드 폴더에서 파일 찾느라 고생하지 마세요!&lt;br /&gt;&lt;br /&gt;
이번 글에서 소개한 &lt;b&gt;확장자 기준 정리 + 오래된 파일 삭제 + 예외 처리&lt;/b&gt; 로직만 적용해도 실무 환경을 훨씬 쾌적하게 만들 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;</description>
      <category>프로그래밍/Python</category>
      <category>Python</category>
      <category>shutil</category>
      <category>다운로드폴더정리</category>
      <category>업무자동화</category>
      <category>파이썬</category>
      <category>파이썬스크립트</category>
      <category>파이썬파일정리</category>
      <category>파일삭제</category>
      <category>파일이동</category>
      <category>파일자동화</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/201</guid>
      <comments>https://qratedev.tistory.com/201#entry201comment</comments>
      <pubDate>Wed, 9 Jul 2025 17:22:10 +0900</pubDate>
    </item>
    <item>
      <title>[Python] openpyxl로 엑셀 차트 자동화하기 &amp;ndash; 라인 차트, 바 차트, 저장까지 실습 예제</title>
      <link>https://qratedev.tistory.com/200</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] openpyxl로 엑셀 차트 자동화하기 – 라인 차트, 바 차트, 저장까지 실습 예제&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀 자동화에서 &lt;b&gt;차트 생성&lt;/b&gt;은 빠질 수 없는 기능입니다.&lt;br /&gt;&lt;br /&gt;이번 글에서는 &lt;b&gt;openpyxl을 사용해 라인 차트(Line Chart), 막대 차트(Bar Chart)&lt;/b&gt;를 생성하고 엑셀 파일에 저장하는 과정을 단계별로 살펴보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. 기본 데이터 생성&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 헤더
ws.append([&quot;월&quot;, &quot;매출&quot;])
# 데이터
data = [
    [1, 100],
    [2, 120],
    [3, 90],
    [4, 150],
    [5, 170],
]
for row in data:
    ws.append(row)

wb.save(&quot;chart_data.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. 라인 차트 추가하기&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
from openpyxl.chart import LineChart, Reference
from openpyxl import load_workbook

wb = load_workbook(&quot;chart_data.xlsx&quot;)
ws = wb.active

# 라인 차트 생성
chart = LineChart()
chart.title = &quot;월별 매출 추이&quot;
chart.style = 13
chart.y_axis.title = &quot;매출&quot;
chart.x_axis.title = &quot;월&quot;

# 데이터 설정 (B열 데이터, 1행은 제목)
data = Reference(ws, min_col=2, min_row=1, max_row=6)
cats = Reference(ws, min_col=1, min_row=2, max_row=6)
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)

# 시트에 차트 추가
ws.add_chart(chart, &quot;D2&quot;)

wb.save(&quot;chart_line.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 막대 차트 추가하기&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
from openpyxl.chart import BarChart

wb = load_workbook(&quot;chart_data.xlsx&quot;)
ws = wb.active

# 막대 차트 생성
bar_chart = BarChart()
bar_chart.title = &quot;월별 매출 막대 그래프&quot;
bar_chart.y_axis.title = &quot;매출&quot;
bar_chart.x_axis.title = &quot;월&quot;

# 데이터 및 범주 지정
data = Reference(ws, min_col=2, min_row=1, max_row=6)
cats = Reference(ws, min_col=1, min_row=2, max_row=6)
bar_chart.add_data(data, titles_from_data=True)
bar_chart.set_categories(cats)

# 시트에 추가
ws.add_chart(bar_chart, &quot;D20&quot;)

wb.save(&quot;chart_bar.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;openpyxl을 활용하면 복잡한 보고서도 파이썬 코드로 자동화할 수 있습니다.&lt;br /&gt;&lt;br /&gt;이번 글에서 소개한 &lt;b&gt;라인 차트, 바 차트&lt;/b&gt;는 실무에서 자주 사용되는 시각화 기능입니다.&lt;br /&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&gt;
  &lt;li&gt;&lt;a href=&quot;https://qratedev.tistory.com/199&quot; target=&quot;_blank&quot;&gt;[Python] openpyxl로 엑셀 자동화하기 – 파일 생성부터 조건부 서식까지&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>프로그래밍/Python</category>
      <category>openpyxl</category>
      <category>Python</category>
      <category>데이터시각화</category>
      <category>라인차트</category>
      <category>막대차트</category>
      <category>업무자동화</category>
      <category>엑셀자동화</category>
      <category>엑셀차트</category>
      <category>파이썬</category>
      <category>파이썬엑셀</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/200</guid>
      <comments>https://qratedev.tistory.com/200#entry200comment</comments>
      <pubDate>Wed, 9 Jul 2025 12:13:47 +0900</pubDate>
    </item>
    <item>
      <title>[Python] openpyxl로 엑셀 자동화하기 &amp;ndash; 파일 생성부터 스타일, 조건부 서식까지 완전 정복</title>
      <link>https://qratedev.tistory.com/199</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] openpyxl로 엑셀 자동화하기 &amp;ndash; 파일 생성부터 스타일, 조건부 서식까지 완전 정복&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑셀은 데이터 관리, 보고서, 자동화 업무에서 빠질 수 없는 도구입니다.&lt;br /&gt;&lt;br /&gt;파이썬의 &lt;b&gt;openpyxl&lt;/b&gt; 라이브러리를 활용하면 반복적인 엑셀 작업을 자동화할 수 있습니다.&lt;br /&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;✅ 1. openpyxl 설치하기&lt;/h2&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;
pip install openpyxl
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. 엑셀 파일 생성 및 데이터 입력&lt;/h2&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;
from openpyxl import Workbook

# 워크북 생성 및 시트 선택
wb = Workbook()
ws = wb.active

# 헤더 및 데이터 작성
ws['A1'] = '이름'
ws['B1'] = '점수'
ws.append(['홍길동', 90])
ws.append(['김철수', 85])

# 파일 저장
wb.save(&quot;sample.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 기존 엑셀 파일 열고 값 수정하기&lt;/h2&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;
from openpyxl import load_workbook

# 파일 열기
wb = load_workbook(&quot;sample.xlsx&quot;)
ws = wb.active

# 데이터 수정
ws['B2'] = 95  # 홍길동 점수 수정

# 다시 저장
wb.save(&quot;sample_modified.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. 셀 서식 지정 (폰트, 정렬, 배경색)&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;
from openpyxl.styles import Font, Alignment, PatternFill

# 워크북 로드
wb = load_workbook(&quot;sample.xlsx&quot;)
ws = wb.active

# 스타일 정의
font = Font(bold=True, color=&quot;FFFFFF&quot;)
align = Alignment(horizontal=&quot;center&quot;)
fill = PatternFill(start_color=&quot;4F81BD&quot;, end_color=&quot;4F81BD&quot;, fill_type=&quot;solid&quot;)

# 헤더 셀에 스타일 적용
for cell in ws[1]:
    cell.font = font
    cell.alignment = align
    cell.fill = fill

wb.save(&quot;sample_styled.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 5. 조건부 서식 (90점 이상이면 녹색 배경)&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;
from openpyxl.formatting.rule import CellIsRule
from openpyxl.styles import PatternFill

# 워크북 로드
wb = load_workbook(&quot;sample.xlsx&quot;)
ws = wb.active

# 조건부 서식 정의
green_fill = PatternFill(start_color=&quot;C6EFCE&quot;, end_color=&quot;C6EFCE&quot;, fill_type=&quot;solid&quot;)
rule = CellIsRule(operator=&quot;greaterThanOrEqual&quot;, formula=[&quot;90&quot;], fill=green_fill)

# 범위에 적용
ws.conditional_formatting.add(&quot;B2:B10&quot;, rule)

wb.save(&quot;sample_conditional.xlsx&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 6. 자주 발생하는 오류 및 해결 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;PermissionError&lt;/code&gt; &amp;rarr; 엑셀 파일이 열려 있는지 확인 후 닫고 실행&lt;/li&gt;
&lt;li&gt;한글 깨짐 방지 &amp;rarr; &lt;code&gt;Font(name=&quot;맑은 고딕&quot;)&lt;/code&gt; 등 한글 폰트 설정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ModuleNotFoundError&lt;/code&gt; &amp;rarr; &lt;code&gt;pip install openpyxl&lt;/code&gt; 설치 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;openpyxl은 엑셀 자동화를 위한 강력한 도구입니다.&lt;br /&gt;&lt;br /&gt;이번 글에서 다룬 기능만으로도 반복 업무를 줄이고 생산성을 높일 수 있습니다.&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>python #openpyxl #엑셀자동화 #파일처리 #업무자동화 #파이썬엑셀 #조건부서식</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/199</guid>
      <comments>https://qratedev.tistory.com/199#entry199comment</comments>
      <pubDate>Tue, 8 Jul 2025 13:16:52 +0900</pubDate>
    </item>
    <item>
      <title>[nextjs] getStaticProps vs getServerSideProps 완벽 비교</title>
      <link>https://qratedev.tistory.com/198</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[nextjs] getStaticProps vs getServerSideProps 완벽 비교&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 &lt;b&gt;페이지 단위로 데이터 패칭 전략&lt;/b&gt;을 선택할 수 있습니다.&lt;br /&gt;그중 가장 자주 쓰이는 함수는 &lt;code&gt;getStaticProps&lt;/code&gt;와 &lt;code&gt;getServerSideProps&lt;/code&gt;입니다.&lt;br /&gt;&lt;br /&gt;이번 글에서는 두 함수의 차이점과 선택 기준을 예제와 함께 정리해봅니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. getStaticProps - 정적 생성 (SSG)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;getStaticProps&lt;/code&gt;는 &lt;b&gt;빌드 타임에 데이터를 가져와 정적 HTML을 생성&lt;/b&gt;합니다.&lt;br /&gt;한 번 빌드하면 그 내용은 CDN에 배포되며, 모든 유저가 동일한 HTML을 받습니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;export async function getStaticProps() {
  const data = await fetchData(); // API 호출 등
  return {
    props: {
      data
    }
  };
}
&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;페이지 속도가 매우 빠름 (정적 HTML)&lt;/li&gt;
&lt;li&gt;변하지 않는 콘텐츠에 적합 (블로그, 마케팅 페이지 등)&lt;/li&gt;
&lt;li&gt;배포 전 데이터가 준비되어 있어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. getServerSideProps - 서버 사이드 렌더링 (SSR)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;getServerSideProps&lt;/code&gt;는 &lt;b&gt;요청이 올 때마다 서버에서 HTML을 생성&lt;/b&gt;합니다.&lt;br /&gt;항상 최신 데이터를 반영해야 할 때 유용합니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;export async function getServerSideProps(context) {
  const data = await fetchData();
  return {
    props: {
      data
    }
  };
}
&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;항상 최신 데이터 제공&lt;/li&gt;
&lt;li&gt;로그인/세션 기반 페이지에 적합&lt;/li&gt;
&lt;li&gt;매 요청마다 서버 로딩이 필요 &amp;rarr; 성능 이슈 주의&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 선택 기준 비교&lt;/h2&gt;
&lt;table border=&quot;1&quot; data-ke-align=&quot;center&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;getStaticProps&lt;/th&gt;
&lt;th&gt;getServerSideProps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&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;불가능 (단, ISR 활용 가능)&lt;/td&gt;
&lt;td&gt;가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;캐싱&lt;/td&gt;
&lt;td&gt;CDN 활용 가능&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;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. 예제 비교&lt;/h2&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// SSG
export async function getStaticProps() {
  const post = await getPostData();
  return { props: { post } };
}

// SSR
export async function getServerSideProps() {
  const user = await getUserData();
  return { props: { user } };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 UI라도 데이터 성격에 따라 SSG or SSR 중 선택할 수 있습니다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;getStaticProps&lt;/code&gt;는 빠르고 캐싱에 유리하며, &lt;code&gt;getServerSideProps&lt;/code&gt;는 실시간성에 강점이 있습니다.&lt;br /&gt;&lt;br /&gt;프로젝트 요구사항에 따라 렌더링 전략을 고르면 퍼포먼스와 UX를 모두 잡을 수 있습니다.&lt;/p&gt;</description>
      <category>프로그래밍/nextjs</category>
      <category>getServerSideProps</category>
      <category>getStaticProps</category>
      <category>next.js</category>
      <category>ssg</category>
      <category>ssr</category>
      <category>리액트</category>
      <category>웹개발</category>
      <category>정적페이지</category>
      <category>코딩강의</category>
      <category>프론트엔드</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/198</guid>
      <comments>https://qratedev.tistory.com/198#entry198comment</comments>
      <pubDate>Sun, 15 Jun 2025 10:00:50 +0900</pubDate>
    </item>
    <item>
      <title>[nextjs] 라우팅 완전 정복 정적/동적 페이지부터 Link까지</title>
      <link>https://qratedev.tistory.com/197</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[nextjs] 라우팅 완전 정복 &amp;ndash; 정적/동적 페이지부터 Link까지&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 &lt;b&gt;파일 기반 라우팅&lt;/b&gt;을 제공합니다.&lt;br /&gt;&lt;code&gt;pages&lt;/code&gt; 폴더 안에 파일을 만들기만 해도 자동으로 URL이 생성되며, &lt;b&gt;정적, 동적, 중첩 라우팅&lt;/b&gt;까지 모두 처리할 수 있습니다.&lt;br /&gt;&lt;br /&gt;이번 글에서는 Next.js 라우팅 시스템의 기본 개념과 실전 사용법을 정리합니다.&lt;/p&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;&lt;code&gt;pages/about.tsx&lt;/code&gt; 파일을 만들면 &lt;code&gt;/about&lt;/code&gt; 경로가 자동 생성됩니다.&lt;br /&gt;파일 구조 = URL 구조라는 점이 Next.js의 핵심입니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;
// pages/about.tsx
export default function About() {
  return &amp;lt;h1&amp;gt;About Page&amp;lt;/h1&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 파일을 만들면 브라우저에서 &lt;code&gt;/about&lt;/code&gt; 경로로 접근 가능합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. 중첩 라우팅&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폴더를 이용해 중첩 페이지도 쉽게 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;
// pages/products/index.tsx
// pages/products/shoes.tsx
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 구조는 각각 &lt;code&gt;/products&lt;/code&gt;, &lt;code&gt;/products/shoes&lt;/code&gt; 경로로 연결됩니다.&lt;br /&gt;폴더 구조 그대로 라우팅된다는 점이 직관적이죠.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 동적 라우팅 (Dynamic Routes)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대괄호 문법을 사용하면 동적인 경로도 쉽게 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;
// pages/post/[id].tsx
import { useRouter } from 'next/router';

export default function Post() {
  const router = useRouter();
  const { id } = router.query;

  return &amp;lt;h1&amp;gt;Post ID: {id}&amp;lt;/h1&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/post/1&lt;/code&gt; 또는 &lt;code&gt;/post/abc&lt;/code&gt;처럼 다양한 URL을 처리할 수 있으며,&lt;br /&gt;이 URL의 파라미터는 &lt;code&gt;useRouter()&lt;/code&gt; 훅으로 받아옵니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. Link 컴포넌트로 페이지 이동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js의 &lt;code&gt;Link&lt;/code&gt; 컴포넌트는 &lt;b&gt;클라이언트 사이드 전환&lt;/b&gt;을 지원하여 페이지 이동 속도가 빠릅니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;
import Link from 'next/link';

export default function Home() {
  return (
    &amp;lt;nav&amp;gt;
      &amp;lt;Link href=&quot;/about&quot;&amp;gt;About으로 이동&amp;lt;/Link&amp;gt;
    &amp;lt;/nav&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 태그 대신 &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt;를 쓰면&lt;br /&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;p data-ke-size=&quot;size16&quot;&gt;Next.js의 라우팅은 파일 기반 구조 덕분에 매우 직관적이고 유연합니다.&lt;br /&gt;&lt;br /&gt;정적, 중첩, 동적 경로를 모두 지원하며, &lt;code&gt;Link&lt;/code&gt; 컴포넌트를 활용하면 사용자 경험도 우수하죠.&lt;/p&gt;</description>
      <category>프로그래밍/nextjs</category>
      <category>next.js</category>
      <category>nextjs라우팅</category>
      <category>react</category>
      <category>ssr</category>
      <category>라우팅</category>
      <category>리액트</category>
      <category>웹개발</category>
      <category>웹프레임워크</category>
      <category>코딩강의</category>
      <category>프론트엔드</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/197</guid>
      <comments>https://qratedev.tistory.com/197#entry197comment</comments>
      <pubDate>Sat, 14 Jun 2025 18:36:45 +0900</pubDate>
    </item>
    <item>
      <title>[nextjs] 왜 써야 할까? &amp;ndash; SSR, SSG, SEO에 강한 리액트 프레임워크</title>
      <link>https://qratedev.tistory.com/196</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[nextjs] 왜 써야 할까? &amp;ndash; SSR, SSG, SEO에 강한 리액트 프레임워크&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 기반 프로젝트를 시작할 때 &lt;b&gt;Next.js&lt;/b&gt;를 고려해본 적 있나요?&lt;br /&gt;&lt;br /&gt;Next.js는 &lt;b&gt;서버 사이드 렌더링(SSR)&lt;/b&gt;, &lt;b&gt;정적 사이트 생성(SSG)&lt;/b&gt;, &lt;b&gt;SEO 최적화&lt;/b&gt; 기능을 갖춘 프레임워크로, 퍼포먼스와 사용자 경험을 동시에 잡을 수 있는 강력한 도구입니다.&lt;br /&gt;이번 글에서는 실무에서 Next.js를 도입해야 하는 이유를 기능별로 정리해봅니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. SSR &amp;ndash; 서버 사이드 렌더링의 이점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 페이지 요청 시 서버에서 HTML을 생성해주는 SSR 기능을 기본 지원합니다.&lt;br /&gt;이 방식은 &lt;b&gt;첫 페이지 로딩 속도를 빠르게&lt;/b&gt; 하고, &lt;b&gt;검색 엔진이 내용을 바로 인식&lt;/b&gt;할 수 있어 SEO에 유리합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빠른 Time-to-First-Byte (TTFB)&lt;/li&gt;
&lt;li&gt;로그인 상태에 따른 맞춤 페이지 제공&lt;/li&gt;
&lt;li&gt;실시간 데이터 기반 콘텐츠 처리에 적합&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. SSG &amp;ndash; 정적 페이지로 초고속 로딩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 사이트 생성(Static Site Generation)은 &lt;b&gt;빌드 타임에 HTML을 미리 생성&lt;/b&gt;하는 방식입니다.&lt;br /&gt;캐싱 및 CDN과의 궁합이 좋아 &lt;b&gt;페이지 로딩 속도가 매우 빠릅니다.&lt;/b&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;대규모 트래픽에서도 안정적인 서비스 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. SEO에 강한 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React는 기본적으로 CSR(Client Side Rendering)이라 SEO가 어렵지만, Next.js는 SSR과 SSG로 이 문제를 해결합니다.&lt;br /&gt;또한 &lt;b&gt;메타태그&lt;/b&gt;, &lt;b&gt;Open Graph&lt;/b&gt;, &lt;b&gt;Twitter Card&lt;/b&gt; 같은 SEO 요소 설정도 매우 쉽습니다.&lt;/p&gt;
&lt;pre class=&quot;html xml&quot;&gt;&lt;code&gt;
import Head from 'next/head';

export default function Home() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Head&amp;gt;
        &amp;lt;title&amp;gt;나의 Next.js 블로그&amp;lt;/title&amp;gt;
        &amp;lt;meta name=&quot;description&quot; content=&quot;Next.js로 만든 SEO 최적화 블로그&quot; /&amp;gt;
      &amp;lt;/Head&amp;gt;
      &amp;lt;main&amp;gt;...&amp;lt;/main&amp;gt;
    &amp;lt;/&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. 동적/정적 페이지의 유연한 조합&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 &lt;b&gt;SSG와 SSR을 페이지 단위로 선택&lt;/b&gt;할 수 있습니다.&lt;br /&gt;상품 상세는 SSR, 전체 상품 리스트는 SSG 등 &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;✅ 5. 결론 &amp;ndash; 실무 친화적 프레임워크&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 &lt;b&gt;빠른 개발&lt;/b&gt;과 &lt;b&gt;높은 생산성&lt;/b&gt;을 제공합니다.&lt;br /&gt;Vercel과의 연동으로 배포도 간편하며, TypeScript, ESLint, 이미지 최적화까지 &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;p data-ke-size=&quot;size16&quot;&gt;Next.js는 단순히 React의 상위 프레임워크가 아니라, &lt;b&gt;웹 퍼포먼스, SEO, 확장성&lt;/b&gt;을 모두 고려한 강력한 툴입니다.&lt;br /&gt;&lt;br /&gt;SSR, SSG를 동시에 지원하는 유연한 구조 덕분에 &lt;b&gt;블로그, 쇼핑몰, SaaS&lt;/b&gt; 등 어떤 프로젝트에도 적합합니다.&lt;br /&gt;&lt;br /&gt;이제 React 프로젝트를 시작한다면, Next.js는 가장 유력한 선택지입니다.&lt;/p&gt;</description>
      <category>프로그래밍/nextjs</category>
      <category>nextjs</category>
      <category>react</category>
      <category>seo</category>
      <category>ssg</category>
      <category>ssr</category>
      <category>vercel</category>
      <category>웹개발</category>
      <category>프론트엔드</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/196</guid>
      <comments>https://qratedev.tistory.com/196#entry196comment</comments>
      <pubDate>Wed, 11 Jun 2025 12:47:54 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #68 - 2025년 4월 4주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/195</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #68 - 2025년 4월 4주차 체중 · 운동 · 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 지난주에 비해 다시 운동 루틴을 조금씩 회복하려고 노력한 주였습니다.&lt;br /&gt;
하지만 여전히 몸살 기운이 남아 있어 완전히 회복되었다고 보긴 어렵고, 주 후반엔 휴식을 병행하며 조절했습니다.&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;4월 21일 ~ 4월 27일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;유산소 운동&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.21 (월)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;87.5&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.22 (화)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.91&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.23 (수)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.84&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;마이마운틴 50분&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.24 (목)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.95&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;마이마운틴 30분&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.25 (금)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.02&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.26 (토)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.9&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.27 (일)&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.03&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;어깨&lt;/td&gt;&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;
  &lt;b&gt;  지난주 마지막 체중:&lt;/b&gt; 88.03kg&lt;br /&gt;
  &lt;b&gt;  이번주 마지막 체중:&lt;/b&gt; 86.03kg&lt;br /&gt;
  &lt;b&gt;  주간 변화:&lt;/b&gt; &lt;span style=&quot;color: #2e8b57;&quot;&gt;-2.00kg 감소&lt;/span&gt;
&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 회복 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난주 감기 몸살 이후, 이번 주에도 완전히 회복되지 않은 상태였습니다.  
여전히 피로감과 몸살 기운이 남아 있어, 운동 빈도는 제한적으로 유지했습니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 3일(수, 목, 일) 동안 웨이트 트레이닝을 진행했고, 수·목 이틀은 유산소(마이마운틴)도 병행했습니다.  
주말엔 휴식 위주로 몸 상태를 점검하면서 강도를 조절했습니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난주 대비 약 2kg 가까이 감소했으며, 이는 컨디션 회복과 식사량 조절의 결과로 해석됩니다.  
체중은 다소 등락이 있었지만 큰 흐름에서는 안정화되는 모습입니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 다음 주 계획&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨디션이 점차 회복되는 만큼, 다음 주에는 운동 빈도와 유산소 시간을 조금씩 늘릴 예정입니다.  
가벼운 아침 스트레칭이나 짧은 유산소부터 천천히 회복 페이스를 끌어올리는 것이 목표입니다.&lt;/p&gt;

&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 다이어트 체중 변화, 회복 상태 체크, 주간 운동 루틴 피드백을 기록한 일지입니다.  
꾸준한 리듬과 자기관리를 바탕으로 건강하게 감량을 이어갑니다.&lt;/p&gt;

&lt;p data-ke-size=&quot;size16&quot; style=&quot;margin-top: 1em;&quot;&gt;
  &lt;b&gt;태그:&lt;/b&gt; 다이어트, 운동일지, 마이마운틴, 체중기록, 몸살, 컨디션관리, 회복기, 식단조절, 주간리뷰, 헬스기록, 유산소운동
&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>다이어트</category>
      <category>마이마운틴</category>
      <category>몸살</category>
      <category>식단조절</category>
      <category>운동일지</category>
      <category>주간리뷰</category>
      <category>체중기록</category>
      <category>컨디션관리</category>
      <category>헬스기록</category>
      <category>회복기</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/195</guid>
      <comments>https://qratedev.tistory.com/195#entry195comment</comments>
      <pubDate>Mon, 26 May 2025 14:52:44 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #67 - 2025년 4월 3주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/194</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #67 - 2025년 4월 3주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 제주도 여행과 감기로 인해 컨디션이 저하되어 운동을 하지 못했습니다.&lt;br /&gt;체중 변화는 후반부에 집중적으로 기록되었으며, 회복과 안정에 초점을 맞춘 한 주였습니다.&lt;/p&gt;
&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;4월 14일 ~ 4월 20일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;유산소 운동&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.14 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.15 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.16 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.17 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.18 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;87.05&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.19 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.49&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.20 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;88.03&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;마이 마운틴 60분&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 마지막 체중:&lt;/b&gt; 86.25kg&lt;br /&gt;&lt;b&gt;  이번주 마지막 체중:&lt;/b&gt; 88.03kg&lt;br /&gt;&lt;b&gt;  주간 변화:&lt;/b&gt; &lt;span style=&quot;color: #d3455b;&quot;&gt;+1.78kg 증가&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 컨디션 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4월 14일부터 18일까지는 제주도 일정으로 인해 운동과 체중 기록이 모두 중단되었습니다. 여행 후반부터는 감기 증상까지 겹쳐 운동을 지속하지 못했습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여행과 회복 기간을 거치며 식습관 및 활동량이 평소보다 낮았고, 후반부 체중은 평소보다 증가한 양상을 보였습니다. 다만 이는 일시적인 수분 증가 혹은 컨디션 영향일 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 운동 루틴을 전혀 소화하지 못했으며, 컨디션 회복이 최우선이었던 시기입니다. 다음 주부터는 가벼운 스트레칭이나 유산소부터 천천히 재개할 예정입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 회복 전략&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적인 피로 누적과 여행 후유증을 최소화하기 위해 충분한 수면, 수분 섭취, 점진적인 활동 복귀가 필요합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 체중 변화 추이와 비운동 주간의 회복 패턴을 중심으로 정리된 기록입니다. 다음 주에는 다시 루틴 복귀를 목표로 계획을 세울 예정입니다.&lt;/p&gt;
&lt;!-- 태그 --&gt;
&lt;p style=&quot;margin-top: 1em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;태그:&lt;/b&gt; 다이어트, 운동쉼, 제주도여행, 감기, 컨디션관리, 회복중, 체중기록, 헬스블로그, 식단이탈, 피드백, 주간리뷰&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>감기</category>
      <category>다이어트</category>
      <category>식단이탈</category>
      <category>운동쉼</category>
      <category>제주도여행</category>
      <category>체중기록</category>
      <category>컨디션관리</category>
      <category>피드백</category>
      <category>헬스블로그</category>
      <category>회복중</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/194</guid>
      <comments>https://qratedev.tistory.com/194#entry194comment</comments>
      <pubDate>Mon, 26 May 2025 13:42:12 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #66 - 2025년 4월 2주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/193</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #66 - 2025년 4월 2주차 체중 · 운동 · 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몸살과 야근 일정이 겹치면서 운동 루틴이 다소 흐트러졌던 한 주였습니다.&lt;br /&gt;다만 초반에는 유산소와 함께 밀도 있게 운동을 진행했고, 후반에는 휴식을 취하며 컨디션 회복에 집중했습니다.&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;4월 7일 ~ 4월 13일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;유산소 운동&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.07 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.31&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;마이마운틴 30분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.08 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.16&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.09 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.03&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;마이마운틴 30분&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.10 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.56&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.11 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.96&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.12 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.67&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.13 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;86.25&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 시작 체중:&lt;/b&gt; 86.31kg&lt;br /&gt;&lt;b&gt;  최저 체중:&lt;/b&gt; 84.67kg&lt;br /&gt;&lt;b&gt;  주간 증가:&lt;/b&gt; +0.06kg&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주 초반에는 비교적 급격한 체중 감소가 있었으나, 주말에는 다시 반등하며 86kg선으로 복귀했습니다. 다소 출렁이는 흐름이었으나, 전체적인 평균선은 유지되고 있습니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 월, 수요일에 웨이트와 유산소를 병행했으며, 나머지 날은 모두 휴식으로 마무리되었습니다. 특히 주중 중반 이후로는 몸살 기운과 야근 일정으로 인해 운동을 지속하지 못한 점이 아쉽습니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 유산소 운동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이마운틴 30분씩 2회를 진행했으며, 강도 있는 유산소로 컨디션 조절에 효과가 있었습니다. 주 후반에 유산소를 병행하지 못한 것은 회복에 초점을 두었습니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 식단 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적으로는 식단 통제가 유지되었지만, 컨디션 난조로 인해 일부 끼니에서 불규칙한 식습관이 발생했을 수 있습니다. 다음 주에는 기본 루틴 회복에 집중할 예정입니다.&lt;/p&gt;

&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 다이어트 체중 기록, 운동 루틴 정리, 유산소 활동 기록, 식단 관리 피드백을 기반으로 한 주간 일지입니다. 꾸준한 추적과 피드백을 통해 건강한 감량 루틴을 이어가고 있습니다.&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>가슴운동</category>
      <category>다이어트</category>
      <category>등운동</category>
      <category>마이마운틴</category>
      <category>식단관리</category>
      <category>운동일지</category>
      <category>유산소운동</category>
      <category>주간리뷰</category>
      <category>체중기록</category>
      <category>헬스</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/193</guid>
      <comments>https://qratedev.tistory.com/193#entry193comment</comments>
      <pubDate>Mon, 26 May 2025 12:34:58 +0900</pubDate>
    </item>
    <item>
      <title>[Python] pandas로 CSV, JSON, Excel 완전 정복 파일 불러오기부터 저장까지 실전 예제</title>
      <link>https://qratedev.tistory.com/192</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] pandas로 CSV, JSON, Excel 완전 정복 &amp;ndash; 파일 불러오기부터 저장까지 실전 예제&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬으로 데이터 분석을 시작한다면 &lt;b&gt;CSV, JSON, Excel&lt;/b&gt; 파일을 다루는 법은 필수입니다.&lt;br /&gt;&lt;br /&gt;이 글에서는 &lt;b&gt;pandas&lt;/b&gt; 라이브러리를 활용해 세 가지 주요 파일 형식을 &lt;b&gt;불러오고 가공한 뒤 저장하는 방법&lt;/b&gt;을 실제 코드와 함께 소개합니다.&lt;br /&gt;업무 자동화나 데이터 전처리에 필요한 기본기를 정리해봤습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. pandas로 다양한 파일 불러오기&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
import pandas as pd

# CSV 불러오기
df_csv = pd.read_csv(&quot;data.csv&quot;)

# JSON 불러오기
df_json = pd.read_json(&quot;data.json&quot;)

# Excel 불러오기 (sheet 지정 가능)
df_excel = pd.read_excel(&quot;data.xlsx&quot;, sheet_name=&quot;Sheet1&quot;)

# 데이터 미리보기
print(df_csv.head())
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. 가공한 데이터 저장하기 (to_*)&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
# CSV로 저장
df_csv.to_csv(&quot;output.csv&quot;, index=False)

# JSON으로 저장 (한글 깨짐 방지)
df_json.to_json(&quot;output.json&quot;, orient=&quot;records&quot;, force_ascii=False, indent=2)

# Excel로 저장
df_excel.to_excel(&quot;output.xlsx&quot;, index=False)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 실전 예제 &amp;ndash; 웹 JSON 데이터를 엑셀로 저장&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;
import requests

# API로 JSON 데이터 받아오기
url = &quot;https://jsonplaceholder.typicode.com/users&quot;
response = requests.get(url)
data = response.json()

# pandas로 변환 후 저장
df = pd.DataFrame(data)
df.to_excel(&quot;users.xlsx&quot;, index=False)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. 자주 발생하는 오류 해결 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;UnicodeDecodeError&lt;/code&gt; 발생 시 &amp;rarr; &lt;code&gt;encoding='utf-8-sig'&lt;/code&gt; 또는 &lt;code&gt;'cp949'&lt;/code&gt;로 인코딩 지정&lt;/li&gt;
&lt;li&gt;Excel 저장 시 오류 발생 &amp;rarr; &lt;code&gt;pip install openpyxl&lt;/code&gt; 설치 필요&lt;/li&gt;
&lt;li&gt;JSON 한글 깨짐 방지 &amp;rarr; &lt;code&gt;force_ascii=False&lt;/code&gt; 옵션 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pandas를 활용하면 파일 형식에 관계없이 데이터를 유연하게 다룰 수 있습니다.&lt;br /&gt;&lt;br /&gt;기초적인 입출력 기능을 익혀두면 분석, 리포트 자동화, 외부 시스템 연동 작업에서도 확실한 기반이 됩니다.&lt;br /&gt;&lt;br /&gt;데이터를 다루는 모든 작업의 시작은 파일 입출력입니다. 필요할 때 참고할 수 있도록 저장해두시면 좋습니다.&lt;/p&gt;
&lt;!-- 태그 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- #Python #pandas #CSV #JSON #Excel #데이터분석 #파일처리 #자동화 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>CSV</category>
      <category>Excel</category>
      <category>JSON</category>
      <category>pandas</category>
      <category>Python</category>
      <category>데이터분석</category>
      <category>업무자동화</category>
      <category>자동화</category>
      <category>파이썬 파일입출력</category>
      <category>파일처리</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/192</guid>
      <comments>https://qratedev.tistory.com/192#entry192comment</comments>
      <pubDate>Wed, 21 May 2025 15:45:00 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #65 - 2025년 3월 5주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/191</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #65 - 2025년 3월 5주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월의 마지막 주와 4월 첫 주가 겹친 이번 주! 체중 기록과 운동 루틴을 정리하면서 한 주를 돌아보는 &lt;b&gt;다이어트 주간 리뷰&lt;/b&gt;입니다. 이번 주는 주말에 체중 기록이 빠졌고, 주중엔 비교적 안정적인 흐름이었습니다.&lt;/p&gt;
&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;3월 31일 ~ 4월 6일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.31 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.84&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.01 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.47&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.02 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.46&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.03 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.62&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.04 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.05&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.05 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;하체, 어깨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;04.06 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;-&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식 (여행)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 최종 체중:&lt;/b&gt; 85.84kg&lt;br /&gt;&lt;b&gt;  변화:&lt;/b&gt; &lt;span style=&quot;color: #d3455b;&quot;&gt;-&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 주말 체중 기록이 빠진 관계로 전체적인 패턴 분석이 다소 어려웠습니다. 주중엔 체중이 하락세였고, 4월 초반까지 비교적 안정적인 흐름을 보였습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주 운동은 총 3회 진행되었습니다. 가슴/삼두, 등/이두, 하체/어깨 루틴으로 구성되었고, 주말엔 여행으로 인해 운동을 건너뛰었습니다. 다음 주부터는 주말 운동 루틴을 다시 점검할 예정입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 식단 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주중엔 식단 관리가 비교적 잘 이루어졌지만, 주말에 여행으로 인해 식단 통제가 어려웠던 점이 아쉬웠습니다. 다음 주엔 여행 영향에서 벗어나 다시 규칙적인 식단으로 복귀할 계획입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 &lt;b&gt;다이어트 체중 기록&lt;/b&gt;, &lt;b&gt;운동 루틴 정리&lt;/b&gt;, &lt;b&gt;식단 관리 피드백&lt;/b&gt;을 바탕으로 한 주간 일지입니다. 체중 감량을 위한 패턴 분석과 꾸준한 운동 기록이 포함되어 있습니다.&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>다이어트 일지</category>
      <category>식단관리</category>
      <category>운동</category>
      <category>일상생활</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/191</guid>
      <comments>https://qratedev.tistory.com/191#entry191comment</comments>
      <pubDate>Fri, 9 May 2025 11:07:26 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #64 - 2025년 3월 4주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/190</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #64 - 2025년 3월 4주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월의 마지막 주! 이번 주도 체중 변화와 운동 루틴을 정리하면서 한 주를 돌아보는 &lt;b&gt;다이어트 주간 리뷰&lt;/b&gt;입니다. 이번 주는 체중이 비교적 큰 변동 없이 유지되었고, 운동 루틴은 상체와 하체 중심으로 나눠서 진행했습니다.&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;3월 24일 ~ 3월 30일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.24 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.80&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.25 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.20&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.26 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.03&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.27 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.89&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.28 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.15&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.29 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.85&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;하체, 어깨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.30 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.89&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 최종 체중:&lt;/b&gt; 85.80kg&lt;br /&gt;&lt;b&gt;  변화:&lt;/b&gt; &lt;span style=&quot;color: #d3455b;&quot;&gt;+0.49kg&lt;/span&gt;&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전반적으로 큰 급등락 없이 유지되긴 했지만, 일요일에 다시 수치가 크게 오르며 마무리되었습니다. 주중엔 조금씩 내려가던 흐름이었으나, 금~일 컨디션이나 식사의 영향이 있었던 듯합니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 총 3회 운동했습니다. 가슴/삼두, 등/이두, 하체/어깨 루틴으로 구성했고, 요일 간 분산도 나쁘지 않았습니다. 휴식일은 무리 없이 조절했으나, 주말에 유산소가 빠진 점은 아쉽네요.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 식단 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주중엔 식단이 안정적이었고, 평소보다 음식 섭취량 조절이 잘 됐던 한 주였습니다. 하지만 주말에 다시 외식이나 배달 영향을 받으며 체중이 반영되었고, 일요일엔 특히 수치 증가가 두드러졌습니다. 다음 주엔 주말 식단 흐름을 더 신경 써보려고 합니다.&lt;/p&gt;

&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 &lt;b&gt;다이어트 체중 기록&lt;/b&gt;, &lt;b&gt;운동 루틴 정리&lt;/b&gt;, &lt;b&gt;식단 관리 피드백&lt;/b&gt;을 바탕으로 한 주간 일지입니다. 체중 감량을 위한 패턴 분석과 꾸준한 운동 기록이 포함되어 있습니다.&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/190</guid>
      <comments>https://qratedev.tistory.com/190#entry190comment</comments>
      <pubDate>Fri, 9 May 2025 00:50:57 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #63 - 2025년 3월 3주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/189</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #63 - 2025년 3월 3주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월의 세 번째 주! 이번 주도 평일과 주말 모두 체중 변화와 운동 루틴을 정리하면서 한 주를 돌아보는 &lt;b&gt;다이어트 주간 리뷰&lt;/b&gt;입니다. 체중은 주 중반부부터 다시 조금씩 오르기 시작했고, 일요일엔 다소 큰 폭의 증가가 있었던 한 주였습니다.&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;3월 17일 ~ 3월 23일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.17 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.26&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.18 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.79&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.19 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.31&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.20 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.20&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.21 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.88&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.22 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.52&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.23 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.80&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;하체, 어깨&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 최종 체중:&lt;/b&gt; 85.31kg&lt;br /&gt;&lt;b&gt;  변화:&lt;/b&gt; &lt;span style=&quot;color: #d3455b;&quot;&gt;+0.49kg&lt;/span&gt;&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 초반엔 비교적 안정적으로 시작했는데, 수요일쯤부터 체중이 조금씩 올라가는 흐름이었어요. 금요일과 토요일엔 다시 살짝 내려갔다가, 일요일에 체중이 꽤 많이 오른 게 확 느껴졌습니다. 주말 컨디션이나 식사 영향이 좀 컸던 것 같고, 일요일 운동했는데도 수치가 올라간 걸 보니 수분이나 음식 무게 영향도 있을 듯해요.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 총 3회 운동했어요. 목요일엔 가슴/삼두, 토요일엔 등/이두, 일요일엔 하체/어깨 루틴. 요일별로 분산도 괜찮았고, 오히려 운동한 날들은 컨디션이 나쁘지 않아서 만족스럽게 마무리한 느낌이에요. 주초엔 운동을 쉬었지만, 후반에 몰아서 잘 챙긴 편이라 밸런스는 괜찮았던 한 주.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 식단 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식단은 전반적으로 평일엔 무리 없었는데, 주말에 약간 흐트러진 감이 있어요. 특히 일요일에는 외식 또는 배달 영향이 좀 있었던 것 같고, 체중 수치에도 바로 반영된 느낌이에요. 다음 주엔 주말 리듬을 조금 더 신경 쓰면서, 유산소를 가볍게라도 꼭 챙겨보려고요.&lt;/p&gt;

&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 &lt;b&gt;다이어트 체중 기록&lt;/b&gt;, &lt;b&gt;운동 루틴 정리&lt;/b&gt;, &lt;b&gt;식단 관리 피드백&lt;/b&gt;을 바탕으로 한 주간 일지입니다. 체중 감량을 위한 패턴 분석과 꾸준한 운동 기록이 포함되어 있습니다.&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>감량리뷰</category>
      <category>다이어트</category>
      <category>다이어트습관</category>
      <category>식단관리</category>
      <category>운동일지</category>
      <category>주간다이어트</category>
      <category>주간체중</category>
      <category>체중기록</category>
      <category>피트니스기록</category>
      <category>헬스루틴</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/189</guid>
      <comments>https://qratedev.tistory.com/189#entry189comment</comments>
      <pubDate>Mon, 21 Apr 2025 15:26:04 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #62 - 2025년 3월 2주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/188</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #62 - 2025년 3월 2주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월의 두 번째 주! 다시 한번 지난 일주일간의 체중 변화와 운동, 식단을 돌아보는 &lt;b&gt;다이어트 주간 리뷰&lt;/b&gt;입니다. 이번 주는 전체적으로 체중이 고르게 유지되다가 마지막 날 급격한 증가가 있었던 흐름이 특징이었습니다.&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;3월 10일 ~ 3월 16일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.10 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.97&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.11 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.34&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.12 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.02&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.13 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.17&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.14 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.27&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.15 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.49&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.16 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;85.31&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;어깨, 하체&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 최종 체중:&lt;/b&gt; 83.92kg&lt;br /&gt;&lt;b&gt;  변화:&lt;/b&gt; &lt;span style=&quot;color: #d3455b;&quot;&gt;+1.39kg&lt;/span&gt;&lt;/p&gt;

&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 초반에 84kg 중반대에서 시작해서 주말쯤 되면서 서서히 올라가는 흐름이었어요. 일요일엔 85kg을 넘기기도 했는데, 아무래도 주말 컨디션이나 식단 영향이 좀 있었던 것 같아요. 전반적으로 보면 큰 변화는 없지만, 그래도 최근 몇 주 중에서는 오름세가 눈에 띄는 주였던 것 같아요. 다음 주엔 다시 리듬 한번 잡아볼 생각입니다.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 수, 토, 일 이렇게 총 3회 운동했는데, 부위별로 잘 나눠서 진행한 편이에요. 수요일엔 가슴/삼두, 토요일엔 등/이두, 일요일엔 어깨/하체 루틴으로. 중간중간 휴식이 좀 많긴 했지만, 컨디션 생각하면 나쁘지 않았던 한 주였던 것 같아요. 일요일 운동할 땐 좀 무겁게 느껴졌지만 그래도 루틴대로 챙긴 건 만족스러웠어요.&lt;/p&gt;

&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 식단 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식단은 평일엔 큰 무리 없이 잘 유지했어요. 특별히 과식하거나 간식을 챙겨 먹은 날은 없었고, 전체적으로 밸런스가 괜찮았던 한 주. 주말에는 약간 흐트러졌던 것 같긴 한데, 그래도 완전히 무너진 건 아니라 그나마 다행이랄까요. 일요일 체중이 좀 올라서 확 체감되긴 했지만, 다음 주엔 주말에도 좀 더 신경 써볼 생각입니다.&lt;/p&gt;

&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 &lt;b&gt;다이어트 체중 기록&lt;/b&gt;, &lt;b&gt;운동 루틴 정리&lt;/b&gt;, &lt;b&gt;식단 관리 피드백&lt;/b&gt;을 바탕으로 한 주간 일지입니다. 체중 감량을 위한 패턴 분석과 꾸준한 운동 기록이 포함되어 있습니다.&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>감량일지</category>
      <category>다이어트</category>
      <category>다이어트피드백</category>
      <category>식단관리</category>
      <category>운동일지</category>
      <category>주간리뷰</category>
      <category>주간체중변화</category>
      <category>체중기록</category>
      <category>피트니스</category>
      <category>헬스기록</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/188</guid>
      <comments>https://qratedev.tistory.com/188#entry188comment</comments>
      <pubDate>Mon, 21 Apr 2025 12:22:07 +0900</pubDate>
    </item>
    <item>
      <title>C# 단위 테스트를 위한 NuGet 패키지 추천 &amp;ndash; 테스트 코드 품질 높이는 필수 도구 6가지</title>
      <link>https://qratedev.tistory.com/187</link>
      <description>&lt;!-- 제목: C# 단위 테스트에 유용한 NuGet 패키지 추천 – 테스트 코드 품질 향상하기 --&gt;

&lt;p&gt;&lt;strong&gt;C# 단위 테스트&lt;/strong&gt;를 보다 효율적으로 작성하고 싶다면, 검증된 &lt;strong&gt;NuGet 테스트 라이브러리&lt;/strong&gt;를 사용하는 것이 핵심입니다. 이 글에서는 테스트 생산성을 높이고, 유지보수를 쉽게 만들어주는 대표적인 NuGet 패키지를 소개합니다.&lt;/p&gt;

&lt;h2&gt;1. xUnit – 널리 쓰이는 테스트 프레임워크&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/xunit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;xUnit&lt;/a&gt;은 Microsoft가 공식으로 권장하는 테스트 프레임워크 중 하나로, 경량이고 확장성이 뛰어납니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[Fact]
public void Add_ReturnsCorrectSum()
{
    var result = calculator.Add(2, 3);
    Assert.Equal(5, result);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 깔끔한 구문, 다양한 테스트 유형 지원, .NET Core/6.0 완벽 호환&lt;/p&gt;

&lt;h2&gt;2. Moq – 객체 목(Mocking) 생성의 표준&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Moq&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Moq&lt;/a&gt;은 인터페이스나 가상 클래스의 동작을 시뮬레이션하여 테스트하는 데 유용한 라이브러리입니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var mock = new Mock&amp;lt;IMailService&amp;gt;();
mock.Setup(m =&amp;gt; m.SendEmail(It.IsAny&amp;lt;string&amp;gt;())).Returns(true);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 단위 테스트에서 외부 의존성 제거에 효과적&lt;/p&gt;

&lt;h2&gt;3. FluentAssertions – 더 읽기 쉬운 Assertion&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/FluentAssertions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FluentAssertions&lt;/a&gt;는 테스트 결과 검증(Assertion)을 사람 친화적인 문장처럼 표현할 수 있게 해줍니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;result.Should().Be(42);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 테스트 실패 시 메시지가 더 명확하고 디버깅이 쉬움&lt;/p&gt;

&lt;h2&gt;4. NSubstitute – Moq 대안으로 인기&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/NSubstitute&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;NSubstitute&lt;/a&gt;는 Moq와 비슷하지만 더 간결한 문법으로 목 객체를 생성할 수 있어 선호되는 경우가 많습니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var service = Substitute.For&amp;lt;IUserService&amp;gt;();
service.GetUser(1).Returns(new User { Name = &quot;홍길동&quot; });&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 간단한 문법, 직관적인 설정&lt;/p&gt;

&lt;h2&gt;5. Coverlet – 코드 커버리지 측정 도구&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/coverlet.collector&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Coverlet&lt;/a&gt;은 테스트 커버리지를 측정하고 리포트를 생성해주는 도구로, Visual Studio 또는 CI 도구와 연동이 잘 됩니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dotnet test /p:CollectCoverage=true&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 테스트 품질을 수치로 확인 가능&lt;/p&gt;

&lt;h2&gt;6. Bogus – 테스트용 더미 데이터 생성&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Bogus&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Bogus&lt;/a&gt;는 가짜 이름, 이메일, 주소 등 다양한 테스트 데이터를 빠르게 생성해줍니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var faker = new Faker&amp;lt;User&amp;gt;()
    .RuleFor(u =&amp;gt; u.Email, f =&amp;gt; f.Internet.Email());&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 시나리오 기반 테스트를 쉽게 준비 가능&lt;/p&gt;

&lt;h2&gt;마무리하며&lt;/h2&gt;
&lt;p&gt;테스트 코드도 결국은 ‘코드’입니다. 생산성과 유지보수성을 고려한다면, 위에서 소개한 NuGet 패키지들을 적극 활용해보세요. &lt;strong&gt;xUnit + Moq + FluentAssertions&lt;/strong&gt; 조합만으로도 상당한 테스트 효율을 누릴 수 있습니다.&lt;/p&gt;

&lt;p&gt;여러분이 애용하는 테스트용 NuGet 패키지가 있다면 댓글로 알려주세요!&lt;/p&gt;</description>
      <category>프로그래밍/C#</category>
      <category>bogus</category>
      <category>coverlet</category>
      <category>csharp</category>
      <category>fluentassertions</category>
      <category>moq</category>
      <category>nsubstitute</category>
      <category>NuGet</category>
      <category>xUnit</category>
      <category>단위테스트</category>
      <category>테스트코드</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/187</guid>
      <comments>https://qratedev.tistory.com/187#entry187comment</comments>
      <pubDate>Wed, 2 Apr 2025 10:35:24 +0900</pubDate>
    </item>
    <item>
      <title>NuGet 패키지 추천 &amp;ndash; C# 개발 생산성 극대화하는 라이브러리 7선</title>
      <link>https://qratedev.tistory.com/186</link>
      <description>&lt;!-- 제목: NuGet 패키지 추천 – C# 개발 생산성 극대화하는 라이브러리 7선 --&gt;

&lt;p&gt;&lt;strong&gt;C# 개발 생산성&lt;/strong&gt;을 높이고 싶은가요? 이 글에서는 실무에서 자주 쓰이는 &lt;strong&gt;NuGet 패키지 추천&lt;/strong&gt; 리스트를 소개합니다. 코드 품질 향상, 유지보수 편의성, 디버깅 효율까지 한 번에 챙겨보세요!&lt;/p&gt;

&lt;h2&gt;1. FluentValidation – 유효성 검사의 정석&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/FluentValidation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FluentValidation&lt;/a&gt;은 모델의 유효성 검사를 깔끔하고 선언적으로 작성할 수 있게 도와줍니다. 특히 MVC, WinForms, WPF 등 어디서나 잘 작동합니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;RuleFor(x =&gt; x.Email).NotEmpty().EmailAddress();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 로직 분리로 코드 가독성이 좋아지고, 테스트 작성이 쉬워집니다.&lt;/p&gt;

&lt;h2&gt;2. Serilog – 강력한 구조적 로깅 시스템&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Serilog&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Serilog&lt;/a&gt;은 다양한 출력 대상(콘솔, 파일, DB 등)에 대응하는 로깅 프레임워크입니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Log.Information(&quot;User {User} logged in at {Time}&quot;, userName, DateTime.Now);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 구조화된 로그로 디버깅과 모니터링이 쉬워집니다.&lt;/p&gt;

&lt;h2&gt;3. Polly – 재시도 로직을 우아하게&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Polly&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Polly&lt;/a&gt;는 실패한 작업을 자동으로 재시도하거나 회로 차단(Circuit Breaker)을 구현할 수 있는 라이브러리입니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Policy.Handle&amp;lt;HttpRequestException&amp;gt;()
    .Retry(3)
    .Execute(() =&amp;gt; CallApi());&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 외부 API나 네트워크 오류에 탄력적인 코드 작성 가능&lt;/p&gt;

&lt;h2&gt;4. AutoMapper – 반복적인 매핑을 줄이자&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/AutoMapper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;AutoMapper&lt;/a&gt;는 DTO ↔ Entity 간의 매핑 코드를 자동화해줍니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var userDto = mapper.Map&amp;lt;UserDto&amp;gt;(user);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 반복 작업 최소화, 유지보수 효율 상승&lt;/p&gt;

&lt;h2&gt;5. MediatR – 깔끔한 CQRS 패턴 구현&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/MediatR&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MediatR&lt;/a&gt;은 메시지 기반 요청/응답 패턴을 구현할 수 있는 패키지입니다. CQRS나 Clean Architecture 구현 시 유용합니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 의존성 분리와 테스트 용이성 증가&lt;/p&gt;

&lt;h2&gt;6. Newtonsoft.Json – JSON 처리의 대표주자&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Newtonsoft.Json&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Newtonsoft.Json&lt;/a&gt;은 JSON 직렬화/역직렬화에 가장 널리 사용되는 패키지입니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var obj = JsonConvert.DeserializeObject&amp;lt;MyClass&amp;gt;(json);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 복잡한 JSON 구조 처리와 커스터마이징에 강력함&lt;/p&gt;

&lt;h2&gt;7. Humanizer – 사람 친화적인 출력 만들기&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Humanizer&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Humanizer&lt;/a&gt;는 날짜, 시간, 숫자 등을 사람이 이해하기 쉬운 표현으로 바꿔줍니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;DateTime.Now.AddHours(-3).Humanize(); // &quot;3 hours ago&quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;✔ 추천 이유:&lt;/strong&gt; 사용자 친화적인 메시지를 쉽게 구현 가능&lt;/p&gt;

&lt;h2&gt;마무리하며&lt;/h2&gt;
&lt;p&gt;위에서 소개한 NuGet 패키지들은 모두 실무에서 유용하게 쓰이는 도구들입니다. 몇 줄의 코드로 개발 효율성을 크게 향상시킬 수 있다는 점에서 적극적으로 도입해볼 만합니다.&lt;/p&gt;

&lt;p&gt;혹시 추가로 소개하고 싶은 NuGet 패키지가 있다면 댓글로 공유해주세요!&lt;/p&gt;</description>
      <category>프로그래밍/C#</category>
      <category>automapper</category>
      <category>csharp</category>
      <category>fluentvalidation</category>
      <category>humanizer</category>
      <category>mediatr</category>
      <category>newtonsoft.json</category>
      <category>NuGet</category>
      <category>Polly</category>
      <category>serilog</category>
      <category>개발생산성</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/186</guid>
      <comments>https://qratedev.tistory.com/186#entry186comment</comments>
      <pubDate>Mon, 31 Mar 2025 12:41:12 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 내 컴퓨터 중복 파일 찾기 &amp;ndash; 해시값 비교로 이미지/문서 정리하기</title>
      <link>https://qratedev.tistory.com/185</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] 내 컴퓨터 중복 파일 찾기 – 해시값 비교로 이미지/문서 정리하기&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
컴퓨터에 파일이 많다 보면 &lt;strong&gt;중복된 파일&lt;/strong&gt;이 생기기 쉽습니다.&lt;br&gt;&lt;br&gt;
이 글에서는 Python을 사용해  
&lt;strong&gt;폴더 내 중복 파일을 자동으로 찾아내는 방법&lt;/strong&gt;을 소개합니다.&lt;br&gt;
`hashlib`으로 &lt;code&gt;MD5 해시값&lt;/code&gt;을 비교하여  
&lt;strong&gt;이름이 달라도 내용이 같은 파일&lt;/strong&gt;을 식별할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. Python 코드 – 중복 파일 탐색기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
import os
import hashlib
from collections import defaultdict

def get_file_hash(filepath):
    hasher = hashlib.md5()
    with open(filepath, 'rb') as f:
        while chunk := f.read(8192):
            hasher.update(chunk)
    return hasher.hexdigest()

def find_duplicate_files(folder_path):
    hash_map = defaultdict(list)

    for root, dirs, files in os.walk(folder_path):
        for filename in files:
            full_path = os.path.join(root, filename)
            try:
                file_hash = get_file_hash(full_path)
                hash_map[file_hash].append(full_path)
            except Exception as e:
                print(f&quot;❌ 오류 발생: {full_path} → {e}&quot;)

    # 중복만 추려서 리턴
    duplicates = {h: paths for h, paths in hash_map.items() if len(paths) &gt; 1}
    return duplicates

# ▶ 사용 예시
target_folder = &quot;D:/Working/2025/2025.03.28&quot;
duplicates = find_duplicate_files(target_folder)

print(f&quot;  중복 파일 검색 결과 ({len(duplicates)} 그룹):&quot;)
for hash_val, files in duplicates.items():
    print(f&quot;\n  해시: {hash_val}&quot;)
    for file in files:
        print(f&quot;  - {file}&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. 실행 결과 예시&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;
  중복 파일 검색 결과 (1 그룹):

  해시: 57203fe4526a8dd1a26f59e4ef209162
  - D:/Working/2025/2025.03.28\1.dll
  - D:/Working/2025/2025.03.28\2.dll
  - D:/Working/2025/2025.03.28\Google.Protobuf.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 어떤 파일이 중복인지 어떻게 판단하나요?&lt;/h2&gt;

&lt;p&gt;
파일을 1줄씩 비교하면 느리기 때문에  
&lt;strong&gt;파일의 MD5 해시값&lt;/strong&gt;을 구해 서로 비교합니다.&lt;br&gt;&lt;br&gt;

- 이름이 달라도, 내용이 같으면 → 해시값 같음  
- 내용이 다르면 → 해시값 다름
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
이 스크립트를 사용하면 &lt;strong&gt;중복 이미지 / 문서 / 백업파일&lt;/strong&gt; 등을  
손쉽게 찾고 정리할 수 있습니다.&lt;br&gt;&lt;br&gt;

필요시 &lt;strong&gt;자동 삭제, 로그 저장, 확장자 필터링&lt;/strong&gt;까지 확장 가능하니  
간단한 정리 스크립트가 필요할 때 꼭 활용해보세요  &lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다!
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Python #중복파일찾기 #파일정리 #hashlib #파일관리 #자동화 --&gt;</description>
      <category>프로그래밍/Python</category>
      <category>hashlib</category>
      <category>Python</category>
      <category>자동화</category>
      <category>중복파일찾기</category>
      <category>파일관리</category>
      <category>파일정리</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/185</guid>
      <comments>https://qratedev.tistory.com/185#entry185comment</comments>
      <pubDate>Fri, 28 Mar 2025 13:26:29 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 나만의 명언 봇 만들기 &amp;ndash; JSON으로 랜덤 출력하기</title>
      <link>https://qratedev.tistory.com/184</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] 나만의 명언 봇 만들기 – JSON으로 랜덤 출력하기&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
하루의 시작을 &lt;strong&gt;짧고 강렬한 명언&lt;/strong&gt;으로 시작하면  
동기부여도 되고 기분도 좋아지죠  &lt;br&gt;&lt;br&gt;

이번 글에서는 Python을 이용해  
&lt;strong&gt;나만의 명언 랜덤 출력기&lt;/strong&gt;를 만드는 방법을 소개합니다.&lt;br&gt;
&lt;code&gt;JSON 파일&lt;/code&gt;을 활용하여 명언을 관리하고,  
매 실행마다 다른 명언이 출력되도록 만들 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. 명언 데이터 (quotes.json)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;
[
  { &quot;quote&quot;: &quot;지금 이 순간을 살아라&quot;, &quot;author&quot;: &quot;괴테&quot; },
  { &quot;quote&quot;: &quot;성공은 준비된 자에게 온다&quot;, &quot;author&quot;: &quot;루이 파스퇴르&quot; },
  { &quot;quote&quot;: &quot;행동은 말보다 강하다&quot;, &quot;author&quot;: &quot;세르반테스&quot; }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
JSON 파일은 &lt;code&gt;quotes.json&lt;/code&gt; 같은 이름으로 저장하면 됩니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. Python 코드 – JSON 명언 랜덤 출력기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
import json
import random

with open(&quot;quotes.json&quot;, encoding=&quot;utf-8&quot;) as f:
    quotes = json.load(f)

quote = random.choice(quotes)
print(f&quot;  \&quot;{quote['quote']}\&quot; - {quote['author']}&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 실행 결과 예시&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;
  &quot;행동은 말보다 강하다&quot; - 세르반테스
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
단 몇 줄의 코드로 나만의 &lt;strong&gt;명언 봇&lt;/strong&gt;을 만들 수 있습니다.&lt;br&gt;&lt;br&gt;
매일 동기부여가 되는 문장을 출력하면서  
&lt;strong&gt;하루의 시작을 조금 더 멋지게&lt;/strong&gt; 바꿔보세요  &lt;br&gt;&lt;br&gt;
도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다!
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Python #명언봇 #json #랜덤출력 #파이썬예제 #동기부여 --&gt;</description>
      <category>프로그래밍/Python</category>
      <category>JSON</category>
      <category>Python</category>
      <category>동기부여</category>
      <category>랜덤출력</category>
      <category>명언봇</category>
      <category>파이썬예제</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/184</guid>
      <comments>https://qratedev.tistory.com/184#entry184comment</comments>
      <pubDate>Fri, 28 Mar 2025 12:57:07 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #61 - 2025년 3월 1주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백</title>
      <link>https://qratedev.tistory.com/183</link>
      <description>&lt;h1 style=&quot;font-size: 1.8em; font-weight: bold;&quot;&gt;[다이어트일지] #61 - 2025년 3월 1주차 체중 &amp;middot; 운동 &amp;middot; 식단 피드백&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월의 첫 주! 식단과 운동을 어떻게 유지했는지 되돌아보는 &lt;b&gt;다이어트 주간 리뷰&lt;/b&gt;입니다. 이번 주는 평일에는 비교적 안정적인 흐름을 보였지만, 주말에 체중이 다시 증가하면서 조금 아쉬움이 남는 한 주였습니다.&lt;/p&gt;
&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  주간 체중 기록&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 0.95em; border: 1px solid #aaa;&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;caption style=&quot;caption-side: top; text-align: left; font-weight: bold; padding: 8px 0;&quot;&gt;3월 3일 ~ 3월 9일 체중 변화 기록&lt;/caption&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #444; color: #fff; text-align: center;&quot;&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;날짜&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;체중(kg)&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;운동 부위&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.03 (월)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.22&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.04 (화)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;84.64&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.05 (수)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;83.66&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;가슴, 삼두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.06 (목)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;83.09&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;등, 이두&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.07 (금)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;82.86&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.08 (토)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;82.76&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;하체, 어깨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;text-align: center;&quot;&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;03.09 (일)&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;83.92&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #aaa; padding: 10px;&quot;&gt;휴식&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  지난주 최종 체중:&lt;/b&gt; 83.96kg&lt;br /&gt;&lt;b&gt;  변화:&lt;/b&gt; &lt;span style=&quot;color: #0593d3;&quot;&gt;-0.04kg&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;margin-top: 2em;&quot; data-ke-size=&quot;size26&quot;&gt;  느낀점&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 체중 변화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 주 초반에 체중이 다소 높게 시작되었지만, 수요일부터 꾸준히 감소하는 흐름을 보이다가, 일요일에 다시 급격하게 체중이 증가하는 패턴을 보였습니다. 이전 주와 마찬가지로 &lt;b&gt;주말 식단과 활동 패턴이 체중 변화에 큰 영향을 주고 있다&lt;/b&gt;는 것을 다시 한번 체감한 한 주였어요. 꾸준히 관리해온 평일의 노력들이 주말에 무너지지 않도록, 앞으로는 &lt;b&gt;주말에도 최소한의 규칙과 절제&lt;/b&gt;를 지키는 것이 중요하겠다는 생각이 들었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 운동 루틴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 휴식일이 많았고, 전체적으로 &lt;b&gt;운동에 대한 집중력이나 에너지가 조금 떨어진 느낌&lt;/b&gt;이었습니다. 살이 살짝 올라서 그런지 평소보다 몸이 무겁게 느껴졌고, 특히 수요일부터 운동을 시작했지만 힘이 덜 실린다는 느낌이 있었어요. 그래도 하체와 어깨 운동은 계획대로 진행했고, 루틴 자체는 여전히 잘 맞는 구조라고 생각됩니다. 다만, 다시 다이어트에 각을 제대로 잡고 &lt;b&gt;운동 강도와 집중도를 조금 더 높여야 할 시점&lt;/b&gt;인 것 같아요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 식단 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평일 식단은 전체적으로 잘 유지되었고, 간식이나 외식 없이 깔끔하게 진행할 수 있었습니다. 문제는 역시 &lt;b&gt;주말 식단&lt;/b&gt;이었어요. 배달 음식이나 간단한 군것질이 반복되다 보니, 일요일 체중에 그대로 반영된 것 같습니다. 체중 감량을 위해선 주중뿐 아니라 주말까지도 일관된 식사 습관과 활동량이 필요하다는 걸 다시 느꼈습니다. 다음 주부터는 &lt;b&gt;주말에 가벼운 유산소 운동을 추가&lt;/b&gt;하고, 배달 음식 섭취도 의식적으로 줄이면서 주말 리듬을 잘 잡는 걸 목표로 삼아야겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;font-size: 0.9em; color: gray;&quot; data-ke-size=&quot;size16&quot;&gt;이 포스트는 &lt;b&gt;다이어트 체중 기록&lt;/b&gt;, &lt;b&gt;운동 루틴 정리&lt;/b&gt;, &lt;b&gt;식단 관리 피드백&lt;/b&gt;을 바탕으로 한 주간 일지입니다. 체중 감량을 위한 패턴 분석과 꾸준한 운동 기록이 포함되어 있습니다.&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>다이어트</category>
      <category>다이어트블로그</category>
      <category>다이어트일기</category>
      <category>몸무게기록</category>
      <category>식단관리</category>
      <category>운동루틴</category>
      <category>주간체중</category>
      <category>체중기록</category>
      <category>체중변화</category>
      <category>헬스일지</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/183</guid>
      <comments>https://qratedev.tistory.com/183#entry183comment</comments>
      <pubDate>Thu, 27 Mar 2025 13:18:57 +0900</pubDate>
    </item>
    <item>
      <title>[Python] 파이썬으로 PDF 내용 추출하는 방법 &amp;ndash; PyMuPDF(fitz) 활용</title>
      <link>https://qratedev.tistory.com/182</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Python] 파이썬으로 PDF 내용 추출하는 방법 – PyMuPDF(fitz) 활용&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
Python으로 PDF 파일을 자동 처리하고 싶을 때,  
&lt;strong&gt;PyMuPDF(fitz)&lt;/strong&gt;는 가장 강력하고 빠른 라이브러리 중 하나입니다.&lt;br&gt;&lt;br&gt;

텍스트 추출, 이미지 추출, 페이지 분리 등  
&lt;strong&gt;문서 자동화 업무&lt;/strong&gt;에 바로 활용할 수 있는 실용적인 기능을 제공합니다.&lt;br&gt;&lt;br&gt;

이 글에서는 PyMuPDF(fitz)를 이용해 &lt;strong&gt;PDF에서 텍스트를 추출하는 방법&lt;/strong&gt;과  
&lt;strong&gt;이미지 저장, 특정 페이지 추출&lt;/strong&gt; 등 실무 예제를 함께 정리해드립니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. PyMuPDF 설치 방법&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pip install pymupdf&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 설치하면 &lt;code&gt;fitz&lt;/code&gt;라는 이름으로 import해서 사용합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. PDF 전체 텍스트 추출하기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
import fitz  # PyMuPDF

doc = fitz.open(&quot;sample.pdf&quot;)  # PDF 열기

for page in doc:
    text = page.get_text()
    print(text)

doc.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;strong&gt;페이지별로 반복하면서 텍스트 추출&lt;/strong&gt; 가능&lt;br&gt;
줄바꿈, 문단 유지도 비교적 잘 되는 편입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 특정 페이지 텍스트 추출하기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
page = doc.load_page(2)  # 3번째 페이지 (0부터 시작)
text = page.get_text()
print(text)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 페이지 수가 많을 경우 &lt;strong&gt;필요한 페이지만 추출&lt;/strong&gt;해서 성능 최적화 가능
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. PDF에서 이미지 추출하기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
for page_number in range(len(doc)):
    page = doc.load_page(page_number)
    images = page.get_images(full=True)

    for img_index, img in enumerate(images):
        xref = img[0]
        pix = fitz.Pixmap(doc, xref)
        if pix.n &amp;lt; 5:  # RGB
            pix.save(f&quot;page{page_number+1}_img{img_index+1}.png&quot;)
        else:  # CMYK → RGB 변환
            pix = fitz.Pixmap(fitz.csRGB, pix)
            pix.save(f&quot;page{page_number+1}_img{img_index+1}.png&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 이미지가 포함된 PDF에서 &lt;strong&gt;내장 이미지 추출&lt;/strong&gt;이 가능합니다.&lt;br&gt;
스크린샷이 아닌 &lt;strong&gt;원본 이미지 그대로&lt;/strong&gt; 추출됩니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 5. 특정 페이지 추출해서 새로운 PDF 만들기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
new_doc = fitz.open()
new_doc.insert_pdf(doc, from_page=2, to_page=4)  # 3~5페이지 복사
new_doc.save(&quot;extracted_pages.pdf&quot;)
new_doc.close()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 기존 PDF에서 &lt;strong&gt;특정 구간만 추출&lt;/strong해 새 문서로 저장 가능  
→ 보고서 자동화, 페이지 분할 작업에 유용합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 6. 텍스트 위치 기반 추출 (고급 기능)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
page = doc.load_page(0)
blocks = page.get_text(&quot;blocks&quot;)  # (x0, y0, x1, y1, &quot;text&quot;, block_no)

for block in blocks:
    x0, y0, x1, y1, text, *_ = block
    print(f&quot;[{x0:.0f}, {y0:.0f}] - {text}&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 좌표 기반 텍스트 분석이 가능하므로  
&lt;strong&gt;표 추출, 영역 지정 추출&lt;/strong&gt; 등의 커스텀 처리가 가능합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;PyMuPDF(fitz)&lt;/code&gt;는 단순한 PDF 읽기를 넘어서  
&lt;strong&gt;텍스트 추출, 이미지 저장, 페이지 조작&lt;/strong&gt;까지 지원하는 강력한 도구입니다.&lt;br&gt;&lt;br&gt;

보고서 자동화, 문서 검수, 데이터 수집 등에  
바로 활용할 수 있는 실무 유틸리티로 추천드립니다  &lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다!
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Python #PDF추출 #PyMuPDF #fitz #문서자동화 #텍스트추출 #이미지추출 #PDF파싱 #파이썬PDF --&gt;</description>
      <category>프로그래밍/Python</category>
      <category>fitz</category>
      <category>pdf추출</category>
      <category>pdf파싱</category>
      <category>pymupdf</category>
      <category>Python</category>
      <category>문서자동화</category>
      <category>이미지추출</category>
      <category>텍스트추출</category>
      <category>파이썬pdf</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/182</guid>
      <comments>https://qratedev.tistory.com/182#entry182comment</comments>
      <pubDate>Wed, 26 Mar 2025 16:55:28 +0900</pubDate>
    </item>
    <item>
      <title>[HTML] &amp;lt;form&amp;gt; 안에서 &amp;lt;section&amp;gt;과 &amp;lt;fieldset&amp;gt; 병행 사용하는 법</title>
      <link>https://qratedev.tistory.com/181</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[HTML] &amp;lt;form&amp;gt; 안에서 &amp;lt;section&amp;gt;과 &amp;lt;fieldset&amp;gt; 병행 사용하는 법&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
HTML에서 &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;을 구성할 때, 입력 항목이 많아지면  
&lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;과 &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;을 병행해 사용하면 구조가 훨씬 깔끔해집니다.&lt;br&gt;&lt;br&gt;

이 글에서는 두 태그의 &lt;strong&gt;차이점&lt;/strong&gt;과 &lt;strong&gt;실무 예제&lt;/strong&gt;를 통해  
&lt;code&gt;폼 구조를 더 명확하게 설계&lt;/code&gt;하는 방법을 소개합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. fieldset vs section – 뭐가 다를까?&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;항목&lt;/th&gt;
      &lt;th&gt;&amp;lt;fieldset&amp;gt;&lt;/th&gt;
      &lt;th&gt;&amp;lt;section&amp;gt;&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;의미&lt;/td&gt;
      &lt;td&gt;입력 항목 그룹 (form control grouping)&lt;/td&gt;
      &lt;td&gt;독립적인 콘텐츠 블록 (document section)&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;legend와 함께 스크린리더 지원↑&lt;/td&gt;
      &lt;td&gt;heading(h1~h6)과 함께 의미 부여&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;시각적 테두리&lt;/td&gt;
      &lt;td&gt;O (기본 테두리 있음)&lt;/td&gt;
      &lt;td&gt;X (스타일 없음)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;
→ &lt;strong&gt;fieldset은 입력 그룹을 묶고, section은 문서 의미를 나누는 구조&lt;/strong&gt;입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. 병행 사용하는 실무 예제&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;form&amp;gt;

  &amp;lt;section aria-labelledby=&quot;account-heading&quot;&amp;gt;
    &amp;lt;h2 id=&quot;account-heading&quot;&amp;gt;계정 정보&amp;lt;/h2&amp;gt;

    &amp;lt;fieldset&amp;gt;
      &amp;lt;legend&amp;gt;로그인 정보&amp;lt;/legend&amp;gt;

      &amp;lt;label for=&quot;email&quot;&amp;gt;이메일&amp;lt;/label&amp;gt;
      &amp;lt;input id=&quot;email&quot; type=&quot;email&quot;&amp;gt;

      &amp;lt;label for=&quot;password&quot;&amp;gt;비밀번호&amp;lt;/label&amp;gt;
      &amp;lt;input id=&quot;password&quot; type=&quot;password&quot;&amp;gt;
    &amp;lt;/fieldset&amp;gt;
  &amp;lt;/section&amp;gt;

  &amp;lt;section aria-labelledby=&quot;profile-heading&quot;&amp;gt;
    &amp;lt;h2 id=&quot;profile-heading&quot;&amp;gt;프로필 정보&amp;lt;/h2&amp;gt;

    &amp;lt;fieldset&amp;gt;
      &amp;lt;legend&amp;gt;기본 정보&amp;lt;/legend&amp;gt;

      &amp;lt;label for=&quot;name&quot;&amp;gt;이름&amp;lt;/label&amp;gt;
      &amp;lt;input id=&quot;name&quot; type=&quot;text&quot;&amp;gt;

      &amp;lt;label for=&quot;birth&quot;&amp;gt;생일&amp;lt;/label&amp;gt;
      &amp;lt;input id=&quot;birth&quot; type=&quot;date&quot;&amp;gt;
    &amp;lt;/fieldset&amp;gt;
  &amp;lt;/section&amp;gt;

  &amp;lt;button type=&quot;submit&quot;&amp;gt;가입하기&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
✔ &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;은 &lt;strong&gt;문서 의미 구조를 나누는 용도&lt;/strong&gt;로 사용되고,&lt;br&gt;
✔ &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;은 &lt;strong&gt;입력 항목 그룹&lt;/strong&gt;을 묶는 데 쓰입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 접근성(A11y) 향상 방법&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;에는 &lt;code&gt;aria-labelledby&lt;/code&gt; 또는 &lt;code&gt;aria-label&lt;/code&gt; 추가&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;legend&amp;gt;&lt;/code&gt;는 해당 입력 그룹의 제목으로 읽힘&lt;/li&gt;
  &lt;li&gt;스크린리더는 heading(h2~h3)과 legend를 구분해서 처리&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
→ 두 태그를 적절히 함께 쓰면 &lt;strong&gt;시각적/논리적/접근성 구조가 모두 완성&lt;/strong&gt;됩니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. 시각적 스타일링 팁&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;
form {
  max-width: 600px;
  margin: auto;
}

section {
  margin-bottom: 2rem;
}

fieldset {
  border: 1px solid #ccc;
  padding: 1rem;
  border-radius: 6px;
}

legend {
  font-weight: bold;
  padding: 0 0.5rem;
  color: #333;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;→ form 전체 레이아웃도 함께 잡아주면 UI가 더 깔끔해집니다.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; 안에서 &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt;과 &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;을 병행하면  
&lt;strong&gt;시맨틱 구조 + UX + 접근성&lt;/strong&gt;을 동시에 챙길 수 있습니다.&lt;br&gt;&lt;br&gt;

대규모 입력 폼, 멀티 스텝 회원가입, 설문 페이지 등에  
꼭 적용해보시길 추천드립니다  &lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다!
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #HTML #form #fieldset #section #폼구조 #웹접근성 #입력폼 #시맨틱웹 #폼디자인 --&gt;</description>
      <category>프로그래밍/html</category>
      <category>FIELDSET</category>
      <category>form</category>
      <category>HTML</category>
      <category>section</category>
      <category>시맨틱웹</category>
      <category>웹접근성</category>
      <category>입력폼</category>
      <category>폼구조</category>
      <category>폼디자인</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/181</guid>
      <comments>https://qratedev.tistory.com/181#entry181comment</comments>
      <pubDate>Wed, 26 Mar 2025 13:13:52 +0900</pubDate>
    </item>
    <item>
      <title>[HTML] &amp;lt;fieldset&amp;gt;과 &amp;lt;legend&amp;gt;로 폼 그룹화하기</title>
      <link>https://qratedev.tistory.com/180</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[HTML] &amp;lt;fieldset&amp;gt;과 &amp;lt;legend&amp;gt;로 폼 그룹화하기&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
HTML에서 &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;과 &lt;code&gt;&amp;lt;legend&amp;gt;&lt;/code&gt;는  
&lt;strong&gt;폼 입력 항목을 그룹화&lt;/strong&gt;하고, &lt;strong&gt;제목을 붙여주는 기능&lt;/strong&gt;을 합니다.&lt;br&gt;&lt;br&gt;

접근성을 높이고, 시각적으로도 그룹을 구분할 수 있게 해주는 매우 중요한 태그입니다.&lt;br&gt;
이 글에서는 &lt;code&gt;fieldset&lt;/code&gt;과 &lt;code&gt;legend&lt;/code&gt;의 사용법과 함께,  
실제 &lt;strong&gt;로그인, 회원가입 폼 예제&lt;/strong&gt;를 통해 설명해드립니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. &amp;lt;fieldset&amp;gt;이란?&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;은 폼 안에서 &lt;strong&gt;입력 그룹을 묶는 컨테이너&lt;/strong&gt;입니다.&lt;br&gt;
해당 그룹은 테두리로 구분되어 표시되며, 관련 입력 요소들을 시각적으로 구분할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. &amp;lt;legend&amp;gt;란?&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;&amp;lt;legend&amp;gt;&lt;/code&gt;는 &lt;code&gt;fieldset&lt;/code&gt;의 &lt;strong&gt;제목&lt;/strong&gt; 역할을 합니다.&lt;br&gt;
보통 그룹의 용도(예: 기본 정보, 연락처 정보 등)를 나타냅니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 기본 예제&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;form&amp;gt;
  &amp;lt;fieldset&amp;gt;
    &amp;lt;legend&amp;gt;로그인 정보&amp;lt;/legend&amp;gt;

    &amp;lt;label for=&quot;email&quot;&amp;gt;이메일:&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;email&quot; id=&quot;email&quot; name=&quot;email&quot;&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;

    &amp;lt;label for=&quot;password&quot;&amp;gt;비밀번호:&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;password&quot; id=&quot;password&quot; name=&quot;password&quot;&amp;gt;

  &amp;lt;/fieldset&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 위 예제는 이메일과 비밀번호를 &lt;code&gt;fieldset&lt;/code&gt;으로 묶고,  
&lt;code&gt;legend&lt;/code&gt;로 그룹 제목을 지정한 구조입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. 실무 회원가입 폼 예제&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;form&amp;gt;
  &amp;lt;fieldset&amp;gt;
    &amp;lt;legend&amp;gt;기본 정보&amp;lt;/legend&amp;gt;

    &amp;lt;label for=&quot;name&quot;&amp;gt;이름:&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;text&quot; id=&quot;name&quot;&amp;gt;

    &amp;lt;label for=&quot;birth&quot;&amp;gt;생년월일:&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;date&quot; id=&quot;birth&quot;&amp;gt;
  &amp;lt;/fieldset&amp;gt;

  &amp;lt;fieldset&amp;gt;
    &amp;lt;legend&amp;gt;연락처 정보&amp;lt;/legend&amp;gt;

    &amp;lt;label for=&quot;email&quot;&amp;gt;이메일:&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;email&quot; id=&quot;email&quot;&amp;gt;

    &amp;lt;label for=&quot;phone&quot;&amp;gt;전화번호:&amp;lt;/label&amp;gt;
    &amp;lt;input type=&quot;tel&quot; id=&quot;phone&quot;&amp;gt;
  &amp;lt;/fieldset&amp;gt;

  &amp;lt;button type=&quot;submit&quot;&amp;gt;가입하기&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 실무에서는 입력 항목을 &lt;strong&gt;논리적 묶음 단위로 그룹화&lt;/strong&gt;해서  
가독성과 접근성을 함께 챙길 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 5. 스타일 커스터마이징 팁&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;
fieldset {
  border: 1px solid #ccc;
  padding: 1rem;
  margin-bottom: 1.5rem;
}

legend {
  font-weight: bold;
  color: #333;
  padding: 0 8px;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 기본 스타일은 브라우저마다 다르므로  
&lt;code&gt;fieldset&lt;/code&gt;과 &lt;code&gt;legend&lt;/code&gt;는 CSS로 커스터마이징하는 것이 일반적입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 6. 접근성과 사용자 경험(UX)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;스크린 리더&lt;/strong&gt;는 &lt;code&gt;legend&lt;/code&gt;를 통해 그룹 이름을 읽어줍니다.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;시각적으로도&lt;/strong&gt; 구분되기 때문에 폼이 복잡해질수록 유용합니다.&lt;/li&gt;
  &lt;li&gt;단순 시각 구분이 아니라, &lt;strong&gt;의미 있는 HTML 구조&lt;/strong&gt;가 된다는 점에서 중요합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt;과 &lt;code&gt;&amp;lt;legend&amp;gt;&lt;/code&gt;는 HTML 폼의 구조를 명확하게 하고  
접근성을 높이며, 사용자 경험을 개선할 수 있는 &lt;strong&gt;중요한 태그&lt;/strong&gt;입니다.&lt;br&gt;&lt;br&gt;

특히 &lt;strong&gt;회원가입, 설정화면, 긴 입력폼&lt;/strong&gt; 등에서는  
반드시 사용하는 것을 추천드립니다.&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #HTML #fieldset #legend #폼그룹화 #form구조 #웹접근성 #입력폼 #회원가입폼 --&gt;</description>
      <category>프로그래밍/html</category>
      <category>FIELDSET</category>
      <category>form구조</category>
      <category>HTML</category>
      <category>legend</category>
      <category>웹접근성</category>
      <category>입력폼</category>
      <category>폼그룹화</category>
      <category>회원가입폼</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/180</guid>
      <comments>https://qratedev.tistory.com/180#entry180comment</comments>
      <pubDate>Wed, 26 Mar 2025 11:29:38 +0900</pubDate>
    </item>
    <item>
      <title>[HTML] placeholder vs label &amp;ndash; 언제 어떤 걸 써야 할까?</title>
      <link>https://qratedev.tistory.com/179</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[HTML] placeholder vs label – 언제 어떤 걸 써야 할까?&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
HTML에서 &lt;code&gt;placeholder&lt;/code&gt;와 &lt;code&gt;label&lt;/code&gt;은 모두 &lt;strong&gt;입력 필드에 대한 힌트&lt;/strong&gt;를 제공하는 요소지만,  
사용 목적과 사용자 경험(UX), 접근성 측면에서 큰 차이가 있습니다.&lt;br&gt;&lt;br&gt;

이 글에서는 두 태그의 차이점과 언제 어떤 상황에서 써야 하는지,  
&lt;strong&gt;실무 기준 예제&lt;/strong&gt;와 함께 정리해보겠습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. placeholder란?&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;input type=&quot;text&quot; placeholder=&quot;이메일 주소를 입력하세요&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
placeholder는 &lt;strong&gt;입력 전 임시로 표시되는 안내 텍스트&lt;/strong&gt;입니다.&lt;br&gt;
입력값을 입력하면 해당 텍스트는 사라집니다.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;✔ 간단한 힌트를 줄 수 있다&lt;/li&gt;
  &lt;li&gt;✘ 입력 후에는 사라지므로 &lt;strong&gt;정보가 유지되지 않는다&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;✘ 화면 낭독기(Screen reader)에서 읽히지 않을 수 있다 (접근성 ↓)&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. label이란?&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;label for=&quot;email&quot;&amp;gt;이메일 주소&amp;lt;/label&amp;gt;
&amp;lt;input id=&quot;email&quot; type=&quot;text&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
label은 해당 입력 필드의 &lt;strong&gt;이름, 설명&lt;/strong&gt;을 명확하게 전달합니다.&lt;br&gt;
클릭 시 입력창으로 포커스를 이동시킬 수 있으며, &lt;strong&gt;접근성을 위한 필수 요소&lt;/strong&gt;입니다.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;✔ 입력값의 의미를 항상 보여줌&lt;/li&gt;
  &lt;li&gt;✔ 시각장애인을 위한 &lt;strong&gt;스크린 리더 호환&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;✔ form 구조에서의 사용성 향상&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 실무 기준 – 언제 무엇을 써야 하나?&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;상황&lt;/th&gt;
      &lt;th&gt;placeholder&lt;/th&gt;
      &lt;th&gt;label&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&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;접근성 (A11y)&lt;/td&gt;
      &lt;td&gt;✘ 지원 약함&lt;/td&gt;
      &lt;td&gt;✅ 스크린리더 호환&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;UX 일관성&lt;/td&gt;
      &lt;td&gt;✘ 텍스트 사라짐&lt;/td&gt;
      &lt;td&gt;✅ 항상 표시됨&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. placeholder + label 같이 쓰는 예시&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;label for=&quot;username&quot;&amp;gt;사용자 이름&amp;lt;/label&amp;gt;
&amp;lt;input id=&quot;username&quot; type=&quot;text&quot; placeholder=&quot;홍길동&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;strong&gt;label은 필수 정보&lt;/strong&gt;로 유지하고, placeholder는 &lt;strong&gt;입력 예시&lt;/strong&gt;로 활용하면  
사용성과 접근성 모두 챙길 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  잘못된 예시 – placeholder만 사용하는 경우&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;lt;input type=&quot;email&quot; placeholder=&quot;이메일 주소&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 입력한 후에는 어떤 정보를 입력해야 했는지 알 수 없습니다.&lt;br&gt;
→ 스크린 리더가 안내하지 못하므로 &lt;strong&gt;접근성 점수에서 감점&lt;/strong&gt;됩니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;placeholder&lt;/code&gt;는 입력 예시를 보여주는 용도로,  
&lt;code&gt;label&lt;/code&gt;은 입력 필드의 이름과 설명을 명확히 하기 위한 필수 요소입니다.&lt;br&gt;&lt;br&gt;

따라서 &lt;strong&gt;placeholder만 사용하는 것은 피하고&lt;/strong&gt;,  
&lt;strong&gt;label은 항상 포함&lt;/strong하면서 보조적으로 placeholder를 사용하는 것이  
&lt;strong&gt;UX + 웹 접근성 + 표준 코딩&lt;/strong 측면에서 가장 바람직합니다.&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #HTML #placeholder #label #웹접근성 #UX디자인 #입력폼 #웹표준 #form구성 --&gt;</description>
      <category>프로그래밍/html</category>
      <category>form구성</category>
      <category>HTML</category>
      <category>label</category>
      <category>placeholder</category>
      <category>UX디자인</category>
      <category>웹접근성</category>
      <category>웹표준</category>
      <category>입력폼</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/179</guid>
      <comments>https://qratedev.tistory.com/179#entry179comment</comments>
      <pubDate>Wed, 26 Mar 2025 09:05:39 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter] CachedNetworkImage 캐시 초기화 / 수동 리프레시 방법</title>
      <link>https://qratedev.tistory.com/178</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Flutter] CachedNetworkImage 캐시 초기화 / 수동 리프레시 방법&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
&lt;code&gt;CachedNetworkImage&lt;/code&gt;는 네트워크 이미지를 &lt;strong&gt;로컬에 저장(캐시)&lt;/strong&gt;해두고  
다음에 같은 URL을 불러오면 빠르게 보여주는 Flutter 이미지 최적화 패키지입니다.&lt;br&gt;&lt;br&gt;

하지만 가끔은 &lt;strong&gt;이미지 캐시를 초기화하거나 강제로 새로고침(refresh)&lt;/strong&gt;하고 싶을 때가 있습니다.&lt;br&gt;
이 글에서는 실무에서 자주 사용하는 &lt;strong&gt;캐시 초기화&lt;/strong&gt; &amp; &lt;strong&gt;수동 리프레시&lt;/strong&gt; 방법을 소개합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. 캐시 전체 초기화 (비우기)&lt;/h2&gt;

&lt;p&gt;
전체 이미지 캐시를 비우고 싶을 땐 &lt;code&gt;DefaultCacheManager&lt;/code&gt;의 &lt;code&gt;emptyCache()&lt;/code&gt;를 사용합니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
import 'package:flutter_cache_manager/flutter_cache_manager.dart';

await DefaultCacheManager().emptyCache();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 이 메서드는 모든 캐시된 이미지 파일을 삭제합니다.&lt;br&gt;
앱 설정 초기화, 로그아웃 시 함께 사용하면 좋습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. 특정 URL 캐시 삭제&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
await DefaultCacheManager().removeFile('https://example.com/image.jpg');
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 특정 이미지만 새로 받아야 할 때 유용합니다.&lt;br&gt;
예: 사용자가 프로필 사진을 바꿨을 때
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 수동 리프레시 구현 (버튼 클릭 시 이미지 다시 로드)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
String imageUrl = 'https://example.com/profile.jpg';
int version = 0;

CachedNetworkImage(
  key: ValueKey(version),
  imageUrl: '$imageUrl?v=$version', // 버전 파라미터로 강제 갱신
  placeholder: (context, url) =&amp;gt; CircularProgressIndicator(),
  errorWidget: (context, url, error) =&amp;gt; Icon(Icons.error),
),
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
// 버튼 클릭 시 버전 증가
ElevatedButton(
  onPressed: () {
    setState(() {
      version++;
    });
  },
  child: Text(&quot;이미지 새로고침&quot;),
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;strong&gt;쿼리 파라미터나 key 변경&lt;/strong&gt;으로 CachedNetworkImage가  
&lt;strong&gt;새로 로드되도록 유도&lt;/strong&gt;할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. 커스텀 CacheManager로 유효기간 설정하기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
class CustomCacheManager extends CacheManager {
  static const key = &quot;customCache&quot;;

  CustomCacheManager() : super(
    Config(
      key,
      stalePeriod: const Duration(hours: 6), // 6시간 후 자동 새로고침
      maxNrOfCacheObjects: 100,
    ),
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
CachedNetworkImage(
  imageUrl: 'https://example.com/image.jpg',
  cacheManager: CustomCacheManager(),
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;code&gt;stalePeriod&lt;/code&gt;를 설정하면 자동으로 갱신 주기를 관리할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;CachedNetworkImage&lt;/code&gt;는 이미지 최적화에 탁월하지만,  
&lt;strong&gt;수동 캐시 제어&lt;/strong&gt; 기능까지 함께 익혀두면  
앱 사용자 경험(UX)을 훨씬 더 매끄럽게 만들 수 있습니다.&lt;br&gt;&lt;br&gt;

이미지 변경이 자주 발생하는 앱이라면 &lt;strong&gt;버전 파라미터 + 캐시 삭제 + 커스텀 CacheManager&lt;/strong&gt; 조합을 적극 활용해보세요!&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Flutter #CachedNetworkImage #이미지캐시 #flutter캐시 #이미지새로고침 #캐시초기화 #flutter성능개선 --&gt;</description>
      <category>프로그래밍/Flutter</category>
      <category>CachedNetworkImage</category>
      <category>Flutter</category>
      <category>flutter성능개선</category>
      <category>flutter캐시</category>
      <category>이미지새로고침</category>
      <category>이미지캐시</category>
      <category>캐시초기화</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/178</guid>
      <comments>https://qratedev.tistory.com/178#entry178comment</comments>
      <pubDate>Tue, 25 Mar 2025 21:04:51 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter] 이미지 로딩 최적화 &amp;ndash; CachedNetworkImage 사용법</title>
      <link>https://qratedev.tistory.com/177</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Flutter] 이미지 로딩 최적화 – CachedNetworkImage 사용법&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
Flutter에서 &lt;code&gt;Image.network()&lt;/code&gt;만 사용하면 이미지가 &lt;strong&gt;스크롤할 때마다 재요청&lt;/strong&gt;되거나  
&lt;strong&gt;깜빡거림(플리커링)&lt;/strong&gt; 현상이 발생할 수 있습니다.&lt;br&gt;&lt;br&gt;

이럴 땐 &lt;strong&gt;CachedNetworkImage&lt;/strong&gt;를 사용하면  
&lt;strong&gt;이미지를 로컬에 캐싱&lt;/strong&gt;해서 불필요한 재로딩을 줄일 수 있어 성능이 훨씬 좋아집니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. CachedNetworkImage란?&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;cached_network_image&lt;/code&gt;는 이미지를 다운로드한 뒤 로컬에 캐싱해서  
다음번에 같은 URL을 요청할 때 &lt;strong&gt;네트워크를 사용하지 않고 빠르게 표시&lt;/strong&gt;해주는 라이브러리입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. 설치 방법&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;
# pubspec.yaml
dependencies:
  cached_network_image: ^3.3.1
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;→ 최신 버전은 pub.dev에서 확인하세요: https://pub.dev/packages/cached_network_image&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. 기본 사용법&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
import 'package:cached_network_image/cached_network_image.dart';

CachedNetworkImage(
  imageUrl: 'https://example.com/image.jpg',
  placeholder: (context, url) =&amp;gt; CircularProgressIndicator(),
  errorWidget: (context, url, error) =&amp;gt; Icon(Icons.error),
)
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;imageUrl&lt;/strong&gt;: 불러올 이미지 주소&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;placeholder&lt;/strong&gt;: 로딩 중 보여줄 위젯&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;errorWidget&lt;/strong&gt;: 이미지 로드 실패 시 대체 위젯&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. BoxFit, height, width 등 커스텀 속성&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
CachedNetworkImage(
  imageUrl: 'https://example.com/profile.jpg',
  width: 120,
  height: 120,
  fit: BoxFit.cover,
  placeholder: (context, url) =&amp;gt; Container(
    width: 120,
    height: 120,
    color: Colors.grey[200],
  ),
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;code&gt;BoxFit.cover&lt;/code&gt;와 함께 사용하면 &lt;strong&gt;프로필 사진, 썸네일 등에 딱 맞게 표시&lt;/strong&gt;할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 5. ListView에서 사용 시 성능 이점&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
ListView.builder(
  itemCount: 10,
  itemBuilder: (context, index) {
    return ListTile(
      leading: CachedNetworkImage(
        imageUrl: 'https://picsum.photos/100?image=$index',
        width: 60,
        height: 60,
        fit: BoxFit.cover,
        placeholder: (context, url) =&amp;gt; CircularProgressIndicator(),
        errorWidget: (context, url, error) =&amp;gt; Icon(Icons.error),
      ),
      title: Text('Item $index'),
    );
  },
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 일반 &lt;code&gt;Image.network&lt;/code&gt;는 스크롤할 때마다 재요청하지만,  
&lt;code&gt;CachedNetworkImage&lt;/code&gt;는 한 번 로딩된 이미지를 &lt;strong&gt;캐시에서 재사용&lt;/strong&gt;합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  실무 팁&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;GIF도 지원하지만 크기 제한이 있으니 주의&lt;/li&gt;
  &lt;li&gt;캐시 만료/초기화는 &lt;code&gt;DefaultCacheManager().emptyCache()&lt;/code&gt; 등으로 가능&lt;/li&gt;
  &lt;li&gt;shimmer 효과나 skeleton UI와 함께 쓰면 UX 향상&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
Flutter 앱의 이미지 성능을 높이고 싶다면  
&lt;code&gt;CachedNetworkImage&lt;/code&gt;는 거의 필수적인 도구입니다.&lt;br&gt;&lt;br&gt;

로딩 시간 단축, UX 향상, 데이터 절약까지 가능하니  
ListView, GridView, 프로필 화면 등에 적극 활용해보세요  &lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다!
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Flutter #이미지최적화 #CachedNetworkImage #이미지로딩 #flutter성능개선 #이미지캐시 #플러터 --&gt;</description>
      <category>프로그래밍/Flutter</category>
      <category>CachedNetworkImage</category>
      <category>Flutter</category>
      <category>flutter성능개선</category>
      <category>이미지로딩</category>
      <category>이미지최적화</category>
      <category>이미지캐시</category>
      <category>플러터</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/177</guid>
      <comments>https://qratedev.tistory.com/177#entry177comment</comments>
      <pubDate>Tue, 25 Mar 2025 20:02:33 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter] 상태관리 뭐 써야 할까? Provider vs Riverpod vs BLoC 비교</title>
      <link>https://qratedev.tistory.com/176</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Flutter] 상태관리 뭐 써야 할까? Provider vs Riverpod vs BLoC 비교&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
Flutter로 앱을 개발하다 보면 &lt;strong&gt;상태관리&lt;/strong&gt;에 대해 반드시 고민하게 됩니다.&lt;br&gt;
처음에는 &lt;code&gt;setState()&lt;/code&gt;로 간단히 처리하지만, 규모가 커지면  
&lt;strong&gt;전역 상태 관리&lt;/strong&gt;, &lt;strong&gt;비동기 처리&lt;/strong&gt;, &lt;strong&gt;모듈화&lt;/strong&gt;가 필요해지죠.&lt;br&gt;&lt;br&gt;

이 글에서는 대표적인 Flutter 상태관리 방식인 &lt;strong&gt;Provider&lt;/strong&gt;, &lt;strong&gt;Riverpod&lt;/strong&gt;, &lt;strong&gt;BLoC&lt;/strong&gt;을 비교하고  
&lt;strong&gt;언제 어떤 걸 선택하면 좋은지&lt;/strong&gt;도 함께 정리해드립니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. Provider – 공식이 인정한 기본 상태관리&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;provider&lt;/code&gt;는 Google에서 만든 공식 추천 패키지입니다.&lt;br&gt;
간단한 구조 + 낮은 학습 난이도로 입문자가 쓰기 좋습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
// provider 예제: ChangeNotifier 사용
class Counter extends ChangeNotifier {
  int value = 0;
  void increment() {
    value++;
    notifyListeners();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
// 사용
ChangeNotifierProvider(
  create: (_) =&amp;gt; Counter(),
  child: Consumer&amp;lt;Counter&amp;gt;(
    builder: (_, counter, __) =&amp;gt; Text('${counter.value}'),
  ),
)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;→ 위 구조는 &lt;strong&gt;단순한 로직&lt;/strong&gt;에서는 충분히 강력합니다.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. Riverpod – Provider의 진화형&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;riverpod&lt;/code&gt;은 Provider의 단점을 개선한 최신 상태관리 방식입니다.&lt;br&gt;
전역 사용 가능, &lt;strong&gt;BuildContext 없이도 접근 가능&lt;/strong&gt;, &lt;strong&gt;더 강력한 타입 안전성&lt;/strong&gt;이 특징입니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
// Riverpod 예제 (flutter_riverpod)
final counterProvider = StateProvider((ref) =&amp;gt; 0);

// 사용
Consumer(
  builder: (context, ref, _) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  },
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;strong&gt;모듈화, 테스트, 리팩토링&lt;/strong&gt;에 강한 구조를 원한다면 Riverpod이 더 적합합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. BLoC – 복잡한 앱에 강한 구조화된 방식&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;bloc&lt;/code&gt;은 이벤트 기반의 구조로 동작하며,  
&lt;code&gt;Stream&lt;/code&gt;과 &lt;code&gt;Sink&lt;/code&gt;를 이용해 데이터 흐름을 제어합니다.&lt;br&gt;
기업용 앱, 복잡한 상태 변화가 많은 앱에 적합합니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
class CounterBloc extends Bloc&amp;lt;CounterEvent, int&amp;gt; {
  CounterBloc() : super(0) {
    on&amp;lt;Increment&amp;gt;((event, emit) =&amp;gt; emit(state + 1));
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-dart&quot;&gt;
// UI에서 Bloc 사용
BlocBuilder&amp;lt;CounterBloc, int&amp;gt;(
  builder: (context, state) {
    return Text('$state');
  },
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 구조가 무겁지만 &lt;strong&gt;대규모 협업, 테스트 자동화&lt;/strong&gt;에 유리합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  상태관리 방식 비교 요약&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;방식&lt;/th&gt;
      &lt;th&gt;장점&lt;/th&gt;
      &lt;th&gt;단점&lt;/th&gt;
      &lt;th&gt;추천 대상&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Provider&lt;/strong&gt;&lt;/td&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;strong&gt;Riverpod&lt;/strong&gt;&lt;/td&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;strong&gt;BLoC&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;명확한 이벤트 흐름, 테스트 강점&lt;/td&gt;
      &lt;td&gt;초기 셋업 복잡&lt;/td&gt;
      &lt;td&gt;대규모 앱, 협업&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
Flutter 상태관리는 앱 규모, 개발자 경험, 유지보수 계획에 따라 선택해야 합니다.&lt;br&gt;
처음에는 Provider → 점점 Riverpod or BLoC으로 옮겨가는 것도 좋은 방법입니다.&lt;br&gt;&lt;br&gt;

✅ 실무에서 가장 많이 쓰는 조합은 &lt;strong&gt;Riverpod + Freezed&lt;/strong&gt;입니다.&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Flutter #상태관리 #Provider #Riverpod #BLoC #StateManagement #Flutter앱개발 #플러터기초 --&gt;</description>
      <category>프로그래밍/Flutter</category>
      <category>BLoC</category>
      <category>Flutter</category>
      <category>Provider</category>
      <category>riverpod</category>
      <category>statemanagement</category>
      <category>상태관리</category>
      <category>플러터기초</category>
      <category>플러터앱개발</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/176</guid>
      <comments>https://qratedev.tistory.com/176#entry176comment</comments>
      <pubDate>Tue, 25 Mar 2025 19:38:06 +0900</pubDate>
    </item>
    <item>
      <title>[TypeScript] 제네릭(Generic) 기초부터 실무까지 정리</title>
      <link>https://qratedev.tistory.com/175</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[TypeScript] 제네릭(Generic) 기초부터 실무까지 정리&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
TypeScript의 &lt;strong&gt;제네릭(Generic)&lt;/strong&gt;은 코드의 &lt;strong&gt;유연성&lt;/strong&gt;과 &lt;strong&gt;재사용성&lt;/strong&gt;을 높여주는 강력한 기능입니다.&lt;br&gt;
함수, 클래스, 인터페이스에서 다양한 타입을 다뤄야 할 때, 제네릭을 사용하면  
&lt;strong&gt;코드 중복 없이 타입 안정성을 유지&lt;/strong&gt;할 수 있습니다.&lt;br&gt;&lt;br&gt;

이 글에서는 &lt;strong&gt;제네릭의 기초 문법&lt;/strong&gt;부터, &lt;strong&gt;실무에서 자주 쓰이는 활용 예제&lt;/strong&gt;까지 정리해드리겠습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 제네릭이란?&lt;/h2&gt;

&lt;p&gt;
제네릭은 타입을 고정하지 않고, 사용할 때 지정할 수 있게 만드는 기능입니다.&lt;br&gt;
기본 문법은 &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt;를 사용하는 형태입니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
// 제네릭 함수 예시
function identity&amp;lt;T&amp;gt;(value: T): T {
  return value;
}

// 사용 예
identity&amp;lt;string&amp;gt;(&quot;hello&quot;); // &quot;hello&quot;
identity&amp;lt;number&amp;gt;(123);    // 123
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 위 함수는 &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt; 등 다양한 타입에 유연하게 대응할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 제네릭 인터페이스&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
interface ApiResponse&amp;lt;T&amp;gt; {
  data: T;
  success: boolean;
  message?: string;
}

const userResponse: ApiResponse&amp;lt;{ name: string; age: number }&amp;gt; = {
  data: { name: &quot;홍길동&quot;, age: 30 },
  success: true,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 제네릭 인터페이스는 API 응답, Form 구조 등 &lt;strong&gt;유형이 다양한 객체 정의&lt;/strong&gt;에 유용합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 제네릭 클래스&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
class StorageBox&amp;lt;T&amp;gt; {
  private items: T[] = [];

  add(item: T) {
    this.items.push(item);
  }

  getAll(): T[] {
    return this.items;
  }
}

const stringBox = new StorageBox&amp;lt;string&amp;gt;();
stringBox.add(&quot;Hello&quot;);
stringBox.add(&quot;World&quot;);

const numbers = new StorageBox&amp;lt;number&amp;gt;();
numbers.add(10);
numbers.add(20);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;code&gt;StorageBox&amp;lt;T&amp;gt;&lt;/code&gt;는 문자열, 숫자 등 &lt;strong&gt;타입에 따라 다른 저장소&lt;/strong&gt;를 만들 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 제네릭에 타입 제약 추가하기 (&lt;code&gt;extends&lt;/code&gt;)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
function getLength&amp;lt;T extends { length: number }&amp;gt;(value: T): number {
  return value.length;
}

getLength(&quot;hello&quot;);        // ✅
getLength([1, 2, 3]);       // ✅
getLength(123);            // ❌ 에러: number는 length 속성이 없음
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;code&gt;extends&lt;/code&gt;를 사용하면 제네릭 타입이 어떤 속성을 &lt;strong&gt;반드시 가지고 있어야 한다는 제약&lt;/strong&gt;을 줄 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 실무에서 많이 쓰는 제네릭 패턴&lt;/h2&gt;

&lt;h3&gt;1. 유연한 유틸리티 함수 만들기&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
function getFirstItem&amp;lt;T&amp;gt;(arr: T[]): T | undefined {
  return arr[0];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;2. 특정 키만 추출하기 (keyof 활용)&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
function getValue&amp;lt;T, K extends keyof T&amp;gt;(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: &quot;홍길동&quot;, age: 25 };
getValue(user, &quot;name&quot;); // &quot;홍길동&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 제네릭이 중요한 이유&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;타입 안정성과 유연성을 동시에 확보할 수 있음&lt;/li&gt;
  &lt;li&gt;코드 중복 없이 다양한 타입에 대응 가능&lt;/li&gt;
  &lt;li&gt;실무에서 API 응답, Form 처리, 상태관리 등에 광범위하게 활용됨&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
TypeScript의 제네릭은 처음엔 어렵게 느껴질 수 있지만,  
한 번 익혀두면 다양한 상황에서 &lt;strong&gt;코드를 깔끔하고 안정적으로 작성&lt;/strong&gt;할 수 있게 됩니다.&lt;br&gt;&lt;br&gt;

앞으로 유틸리티 타입(Partial, Pick 등)과 함께 사용하는 패턴도 소개할 예정입니다!&lt;br&gt;
도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #TypeScript #제네릭 #Generic #타입스크립트기초 #함수제네릭 #인터페이스제네릭 #타입유연성 #실무코딩 --&gt;</description>
      <category>프로그래밍/typescript</category>
      <category>Generic</category>
      <category>typescript</category>
      <category>실무코딩</category>
      <category>인터페이스제네릭</category>
      <category>제네릭</category>
      <category>타입스크립트기초</category>
      <category>타입유연성</category>
      <category>함수제네릭</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/175</guid>
      <comments>https://qratedev.tistory.com/175#entry175comment</comments>
      <pubDate>Tue, 25 Mar 2025 18:53:01 +0900</pubDate>
    </item>
    <item>
      <title>[HTML] 특수 문자(&amp;amp;nbsp;, &amp;amp;lt;, &amp;amp;copy;) 정리 &amp;ndash; HTML Entities 모음</title>
      <link>https://qratedev.tistory.com/174</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[HTML] 특수 문자(&amp;nbsp;, &amp;lt;, &amp;copy;) 정리 – HTML Entities 모음&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
HTML에서 &lt;strong&gt;특수 문자(HTML Entities)&lt;/strong&gt;는 코드 상으로 직접 입력이 불가능하거나,  
입력 시 문제가 생길 수 있는 문자를 &lt;code&gt;&amp;코드;&lt;/code&gt; 형태로 작성하는 방식입니다.&lt;br&gt;&lt;br&gt;

예를 들어, &lt;code&gt;&amp;lt;&lt;/code&gt;는 “작다(&lt;)” 기호를 의미하고,  
&lt;code&gt;&amp;copy;&lt;/code&gt;는 저작권 표시인 “©”로 표시됩니다.&lt;br&gt;&lt;br&gt;

이 글에서는 &lt;strong&gt;자주 사용되는 특수 문자와 엔티티 코드&lt;/strong&gt;를 정리해드릴게요.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 기본 특수 문자 모음&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;문자&lt;/th&gt;
      &lt;th&gt;Entity 코드&lt;/th&gt;
      &lt;th&gt;의미&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;앰퍼샌드 (&amp;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;lt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;작다 (&amp;lt;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;gt;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;크다 (&amp;gt;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;quot;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;quot;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;큰따옴표 (&quot;)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;apos;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;apos;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;작은따옴표 (')&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;nbsp;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;nbsp;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;공백 (Non-breaking space)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 기호/문자 관련 Entity 코드&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;문자&lt;/th&gt;
      &lt;th&gt;Entity 코드&lt;/th&gt;
      &lt;th&gt;의미&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;copy;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;copy;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;저작권 (©)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;reg;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;reg;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;등록상표 (®)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;euro;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;euro;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;유로 화폐 (€)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;yen;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;yen;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;엔 화폐 (¥)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;cent;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;cent;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;센트 기호 (¢)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;#169;&lt;/td&gt;
      &lt;td&gt;&lt;code&gt;&amp;#169;&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;숫자 코드로 표현한 저작권 기호&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 이모지 &amp; 유니코드 특수문자 (참고)&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;
&amp;#128512;  &lt;!--   --&gt;
&amp;#x1F60A;  &lt;!--   --&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;code&gt;&amp;#x1F60A;&lt;/code&gt; 형태는 유니코드 16진수 표현입니다.&lt;br&gt;
HTML에서도 이모지 사용 가능하지만, &lt;strong&gt;폰트 호환성&lt;/strong&gt;을 고려해야 합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 실무에서 자주 쓰이는 케이스&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;HTML 코드 그대로 보여주고 싶을 때:&lt;/strong&gt; &amp;lt;div&amp;gt;Hello&amp;lt;/div&amp;gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;문장 중간에 공백 유지:&lt;/strong&gt; Hello&amp;nbsp;&amp;nbsp;World!&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;텍스트에 기호 삽입:&lt;/strong&gt; &amp;copy; 2025 Bok Corp.&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
HTML 특수 문자는 웹에서 &lt;strong&gt;코드 충돌 없이 특수 기호를 표현&lt;/strong&gt;할 수 있게 도와주는 기능입니다.&lt;br&gt;
특히 HTML/CSS/JS를 블로그나 포트폴리오에 보여줄 때 꼭 필요한 요소이기도 하죠.&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #HTML #특수문자 #엔티티코드 #nbsp #lt #copy #html기초 #웹개발 --&gt;</description>
      <category>프로그래밍/html</category>
      <category>Copy</category>
      <category>HTML</category>
      <category>HTML기초</category>
      <category>LT</category>
      <category>nbsp</category>
      <category>엔티티코드</category>
      <category>웹개발</category>
      <category>특수문자</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/174</guid>
      <comments>https://qratedev.tistory.com/174#entry174comment</comments>
      <pubDate>Tue, 25 Mar 2025 12:57:52 +0900</pubDate>
    </item>
    <item>
      <title>[Tomcat] 메모리 설정 방법 &amp;ndash; JAVA_OPTS / Heap Size 튜닝 완벽 정리</title>
      <link>https://qratedev.tistory.com/173</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[Tomcat] 메모리 설정 방법 – JAVA_OPTS / Heap Size 튜닝 완벽 정리&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
톰캣(Tomcat)을 운영하다 보면 &lt;strong&gt;OutOfMemoryError&lt;/strong&gt;나 &lt;strong&gt;서버 느림&lt;/strong&gt; 현상을 겪을 수 있습니다.&lt;br&gt;
이럴 때 가장 먼저 확인해야 할 부분은 &lt;strong&gt;JVM 메모리 설정&lt;/strong입니다.&lt;br&gt;&lt;br&gt;
이 글에서는 &lt;strong&gt;JAVA_OPTS를 이용한 메모리 설정&lt;/strong&gt;,  
&lt;code&gt;-Xms&lt;/code&gt;, &lt;code&gt;-Xmx&lt;/code&gt; 옵션 의미,  
그리고 &lt;strong&gt;실무에서 추천하는 힙 사이즈 조정 팁&lt;/strong&gt;까지 모두 정리해드립니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ JAVA_OPTS vs CATALINA_OPTS 차이&lt;/h2&gt;

&lt;p&gt;
톰캣에서 JVM 옵션을 설정할 때는 &lt;code&gt;JAVA_OPTS&lt;/code&gt;나 &lt;code&gt;CATALINA_OPTS&lt;/code&gt; 환경변수를 사용할 수 있습니다.
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;JAVA_OPTS&lt;/strong&gt;: 톰캣 실행 시 항상 적용됨 (start, stop 등 모두)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CATALINA_OPTS&lt;/strong&gt;: &lt;strong&gt;톰캣 구동 시에만 적용&lt;/strong&gt; (start 시에만)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
→ 보통 &lt;strong&gt;메모리 관련 설정은 JAVA_OPTS&lt;/strong&gt; 또는 &lt;strong&gt;CATALINA_OPTS 둘 중 하나에만&lt;/strong&gt; 설정하면 됩니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ setenv.sh (또는 setenv.bat)로 설정&lt;/h2&gt;

&lt;p&gt;
톰캣 홈 경로의 &lt;code&gt;bin&lt;/code&gt; 폴더에 &lt;code&gt;setenv.sh&lt;/code&gt; (리눅스) 또는 &lt;code&gt;setenv.bat&lt;/code&gt; (윈도우)을 만들어 설정합니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# setenv.sh (리눅스/macOS)
export JAVA_OPTS=&quot;-Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-bat&quot;&gt;:: setenv.bat (Windows)
set JAVA_OPTS=-Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
톰캣이 실행될 때 이 파일이 자동으로 불려옵니다.  
없으면 직접 만들어도 무방합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 주요 JVM 메모리 옵션 설명&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;옵션&lt;/th&gt;
      &lt;th&gt;설명&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;-Xms&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;JVM 시작 시 할당할 최소 힙 크기&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;-Xmx&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;JVM이 사용할 수 있는 최대 힙 크기&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;-XX:PermSize&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;클래스 메타데이터 저장 영역 초기 크기 (Java 7 이하)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;-XX:MaxPermSize&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;PermGen 최대 크기 (Java 7 이하)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;-XX:MaxMetaspaceSize&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;(Java 8 이상) PermGen 대신 Metaspace 영역 최대 크기&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt; Java 8 이상에서는 PermSize 대신 &lt;code&gt;Metaspace&lt;/code&gt; 옵션을 사용해야 합니다.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 실무에서 추천하는 힙 설정 예시&lt;/h2&gt;

&lt;p&gt;
운영 환경에서 메모리 사용량이 많지 않다면 아래와 같이 설정합니다:
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
export JAVA_OPTS=&quot;-Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;메모리 많이 쓰는 WAS라면:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;
export JAVA_OPTS=&quot;-Xms1024m -Xmx2048m -XX:MaxMetaspaceSize=512m&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;주의:&lt;/strong&gt; 서버 메모리(RAM) 크기를 초과하지 않도록 설정하세요.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 적용 후 확인 방법&lt;/h2&gt;

&lt;p&gt;
톰캣 구동 후 아래 명령어로 메모리 설정이 제대로 반영됐는지 확인할 수 있습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ps aux | grep tomcat&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;또는 &lt;code&gt;jcmd&lt;/code&gt;, &lt;code&gt;jvisualvm&lt;/code&gt;, &lt;code&gt;jconsole&lt;/code&gt; 등 툴로도 확인 가능&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
톰캣이 느리거나 OutOfMemory 에러가 발생한다면  
가장 먼저 JVM 메모리 설정을 점검해보세요.&lt;br&gt;&lt;br&gt;

&lt;code&gt;setenv.sh&lt;/code&gt; 파일을 통해 &lt;strong&gt;-Xms / -Xmx&lt;/strong&gt;를 명확하게 설정하면  
서버 안정성도 높아지고 성능도 개선됩니다.&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #Tomcat #JAVA_OPTS #메모리설정 #HeapSize #톰캣속도 #서버튜닝 #JVM옵션 #Tomcat설정 --&gt;</description>
      <category>프로그래밍/tomcat</category>
      <category>heapsize</category>
      <category>java_opts</category>
      <category>JVM옵션</category>
      <category>tomcat</category>
      <category>메모리설정</category>
      <category>서버튜닝</category>
      <category>톰캣설정</category>
      <category>톰캣속도</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/173</guid>
      <comments>https://qratedev.tistory.com/173#entry173comment</comments>
      <pubDate>Tue, 25 Mar 2025 12:53:44 +0900</pubDate>
    </item>
    <item>
      <title>[C#] Quartz.NET 스케줄링 작업 자동화 &amp;ndash; 기본 사용법부터 실무 적용까지</title>
      <link>https://qratedev.tistory.com/172</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[C# Quartz.NET] 스케줄링 작업 자동화 – 기본 사용법부터 실무 적용까지&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
C#에서 &lt;strong&gt;반복 작업&lt;/strong&gt;이나 &lt;strong&gt;예약된 작업&lt;/strong&gt;을 실행하려면  
&lt;strong&gt;Quartz.NET&lt;/strong&gt;을 사용하는 것이 가장 일반적입니다.&lt;br&gt;&lt;br&gt;

Quartz는 &lt;strong&gt;정해진 시간마다 특정 작업을 실행&lt;/strong&gt;하거나,  
복잡한 &lt;strong&gt;크론 표현식(Cron Expression)&lt;/strong&gt;을 설정하여  
정교한 스케줄링을 구현할 수 있는 라이브러리입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ Quartz.NET 설치하기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;
// NuGet으로 설치
Install-Package Quartz
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. 기본 Job 클래스 만들기&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// IJob을 상속한 작업 클래스
public class HelloJob : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        Console.WriteLine($&quot;[{DateTime.Now}] Hello Quartz!&quot;);
        return Task.CompletedTask;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
Quartz는 실행할 작업을 &lt;code&gt;IJob&lt;/code&gt; 인터페이스를 통해 정의합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. Scheduler 설정 및 Job 등록&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
IScheduler scheduler = await StdSchedulerFactory.GetDefaultScheduler();
await scheduler.Start();

// Job 생성
IJobDetail job = JobBuilder.Create&amp;lt;HelloJob&amp;gt;()
    .WithIdentity(&quot;helloJob&quot;, &quot;group1&quot;)
    .Build();

// 트리거 설정 (5초마다 실행)
ITrigger trigger = TriggerBuilder.Create()
    .WithIdentity(&quot;helloTrigger&quot;, &quot;group1&quot;)
    .StartNow()
    .WithSimpleSchedule(x =&amp;gt; x
        .WithIntervalInSeconds(5)
        .RepeatForever())
    .Build();

// 스케줄러에 Job과 Trigger 등록
await scheduler.ScheduleJob(job, trigger);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 위 예제는 프로그램이 실행되자마자 &lt;strong&gt;5초 간격으로 HelloJob을 반복 실행&lt;/strong&gt;하는 구조입니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. Cron 표현식으로 특정 시간에 실행&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 매일 오전 9시에 실행
ITrigger cronTrigger = TriggerBuilder.Create()
    .WithIdentity(&quot;dailyTrigger&quot;, &quot;group1&quot;)
    .WithCronSchedule(&quot;0 0 9 ? * *&quot;) // 초 분 시 일 월 요일
    .Build();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
&lt;strong&gt;Cron 표현식&lt;/strong&gt;을 사용하면  
매주 특정 요일, 특정 시간에만 실행되도록 정밀하게 제어할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. 실무 적용 팁&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;로그 파일 정리&lt;/strong&gt;, &lt;strong&gt;백업 작업&lt;/strong&gt;, &lt;strong&gt;메일 전송&lt;/strong&gt; 등에 활용 가능&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;JobDataMap&lt;/code&gt;을 통해 Job에 매개변수 전달 가능&lt;/li&gt;
  &lt;li&gt;윈도우 서비스로 등록하면 &lt;strong&gt;항상 백그라운드에서 작동&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// JobDataMap 사용 예시
IJobDetail job = JobBuilder.Create&amp;lt;EmailJob&amp;gt;()
    .UsingJobData(&quot;recipient&quot;, &quot;admin@example.com&quot;)
    .Build();
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 5. ASP.NET Core에서 Quartz 사용하기&lt;/h2&gt;

&lt;p&gt;
.NET Core에서는 &lt;strong&gt;Quartz.Extensions.Hosting&lt;/strong&gt; 패키지를 사용하면  
DI 기반으로 Quartz를 쉽게 등록하고 관리할 수 있습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;
// 패키지 설치
Install-Package Quartz.Extensions.Hosting
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// Program.cs
builder.Services.AddQuartz(q =&amp;gt;
{
    q.UseMicrosoftDependencyInjectionJobFactory();

    var jobKey = new JobKey(&quot;HelloJob&quot;);
    q.AddJob&amp;lt;HelloJob&amp;gt;(opts =&amp;gt; opts.WithIdentity(jobKey));
    q.AddTrigger(opts =&amp;gt; opts
        .ForJob(jobKey)
        .WithSimpleSchedule(x =&amp;gt; x.WithIntervalInSeconds(10).RepeatForever()));
});

builder.Services.AddQuartzHostedService(q =&amp;gt; q.WaitForJobsToComplete = true);
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
Quartz.NET은 &lt;strong&gt;단순 반복 작업부터 복잡한 일정 작업까지&lt;/strong&gt;  
다양한 스케줄링을 안정적으로 처리할 수 있는 강력한 도구입니다.&lt;br&gt;
C# 실무에서 백그라운드 작업 자동화, 주기적 로직 실행, 예약 시스템 등을 구성할 때  
Quartz는 매우 유용하게 사용될 수 있습니다.&lt;br&gt;&lt;br&gt;

도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #C# #Quartz #스케줄링 #예약작업 #백그라운드작업 #윈도우서비스 #Cron #Quartz.NET #자동화 #실무팁 --&gt;</description>
      <category>프로그래밍/C#</category>
      <category>C#</category>
      <category>cron</category>
      <category>QUARTZ</category>
      <category>quartz.net</category>
      <category>백그라운드작업</category>
      <category>스케줄링</category>
      <category>실무팁</category>
      <category>예약작업</category>
      <category>윈도우서비스</category>
      <category>자동화</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/172</guid>
      <comments>https://qratedev.tistory.com/172#entry172comment</comments>
      <pubDate>Mon, 24 Mar 2025 14:59:37 +0900</pubDate>
    </item>
    <item>
      <title>[DevExpress] SplashScreenManager로 로딩 화면 만들기 &amp;ndash; GridView 데이터 바인딩 UX 개선</title>
      <link>https://qratedev.tistory.com/171</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[DevExpress] SplashScreenManager로 로딩 화면 만들기 &amp;ndash; GridView 데이터 바인딩 UX 개선&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 데이터를 로딩할 때 화면이 멈추거나, 사용자에게 아무런 반응이 없으면 UX가 매우 떨어집니다. 이럴 때는 DevExpress에서 제공하는 &lt;b&gt;&lt;code&gt;SplashScreenManager&lt;/code&gt;&lt;/b&gt;를 사용하여 &lt;b&gt;로딩 화면&lt;/b&gt;을 구성하면 좋습니다.&lt;br /&gt;&lt;br /&gt;이 글에서는 &lt;b&gt;GridView에 데이터를 지연 로딩하면서 SplashScreen&lt;/b&gt;을 띄우는 실제 코드 예제를 정리해보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. Splash 화면이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DevExpress의 &lt;code&gt;SplashScreenManager&lt;/code&gt;는 로딩 중일 때 ProgressBar, 텍스트 등을 보여주는 &lt;b&gt;비동기 UI 컴포넌트&lt;/b&gt;입니다.&lt;br /&gt;단순한 &quot;잠시 기다려 주세요&quot; 메시지부터, 동적인 애니메이션 로딩 화면까지 만들 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 2. 설치 전 준비&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DevExpress WinForms 라이브러리 설치&lt;/b&gt;되어 있어야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트에 SplashScreen Form 추가&lt;/b&gt; (DevExpress 메뉴 &amp;rarr; &quot;Add New Item&quot; &amp;rarr; &quot;SplashScreen&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. GridControl + SplashScreen 연동 예제&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;
private async void MainForm_Load(object sender, EventArgs e)
{
    // 1. SplashScreen 표시
    SplashScreenManager.ShowForm(this, typeof(MyWaitForm), true, true, false);

    try
    {
        // 2. 백그라운드에서 데이터 로딩
        var data = await Task.Run(() =&amp;gt; GetDataFromDatabase());

        // 3. Grid에 바인딩 (렌더링 최적화)
        gridView.BeginUpdate();
        gridControl.DataSource = data;
        gridView.EndUpdate();
    }
    finally
    {
        // 4. SplashScreen 닫기
        SplashScreenManager.CloseForm();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의:&lt;/b&gt; &lt;code&gt;ShowForm()&lt;/code&gt;은 UI 스레드에서 호출해야 하고, &lt;code&gt;Task.Run&lt;/code&gt;은 백그라운드 스레드에서 데이터 로딩을 담당합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. 커스텀 Splash 화면 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 Splash 화면 외에도 커스텀 화면을 디자인할 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Solution Explorer &amp;rarr; Add &amp;rarr; New Item &amp;rarr; DevExpress SplashScreen&lt;/li&gt;
&lt;li&gt;ProgressBar, Label, PictureBox 등을 자유롭게 배치&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MyWaitForm.cs&lt;/code&gt;가 생성됨&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Splash 화면 클래스명은 예제처럼 &lt;code&gt;MyWaitForm&lt;/code&gt;으로 설정해 주세요.&lt;br /&gt;이 폼은 &lt;code&gt;ShowForm()&lt;/code&gt;에서 사용됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  팁 &amp;ndash; 비동기 로딩 + UX 둘 다 잡기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;폼은 먼저 표시&lt;/b&gt;되고, 데이터는 &lt;b&gt;비동기로 로딩&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;로딩 중이라는 것을 SplashScreen으로 &lt;b&gt;시각적으로 안내&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BeginUpdate / EndUpdate&lt;/code&gt;로 렌더링 최적화&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Task.Run&lt;/code&gt;과 &lt;code&gt;await&lt;/code&gt;로 UI 멈춤 없이 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 경험을 고려한 로딩 화면은 작은 차이지만 &lt;b&gt;프로그램 완성도에 큰 차이&lt;/b&gt;를 만듭니다.&lt;br /&gt;DevExpress의 SplashScreenManager는 이를 쉽고 깔끔하게 구현할 수 있는 좋은 도구입니다.&lt;br /&gt;&lt;br /&gt;실무에서 GridView나 TreeList 등에 대용량 데이터를 처리하신다면 꼭 Splash 적용을 검토해보세요!&lt;br /&gt;&lt;br /&gt;도움이 되셨다면 &lt;b&gt;공감 / 댓글&lt;/b&gt; 부탁드립니다  &lt;/p&gt;
&lt;!-- 태그 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- #DevExpress #SplashScreenManager #GridView #로딩화면 #비동기로딩 #WinForms #C# #UX개선 #데이터바인딩 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍/C#</category>
      <category>C#</category>
      <category>DevExpress</category>
      <category>gridview</category>
      <category>SplashScreenManager</category>
      <category>ux개선</category>
      <category>winforms</category>
      <category>데이터바인딩</category>
      <category>로딩화면</category>
      <category>비동기로딩</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/171</guid>
      <comments>https://qratedev.tistory.com/171#entry171comment</comments>
      <pubDate>Mon, 24 Mar 2025 13:30:31 +0900</pubDate>
    </item>
    <item>
      <title>[C#] Devexpress GridControl DataSource 지연 로딩으로 속도 최적화하기</title>
      <link>https://qratedev.tistory.com/170</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[DevExpress] GridControl DataSource 지연 로딩으로 속도 최적화하기&lt;/h1&gt;
&lt;!-- 본문 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DevExpress의 &lt;b&gt;GridControl / GridView&lt;/b&gt;에 데이터를 바인딩할 때, 바로 &lt;code&gt;DataSource&lt;/code&gt;를 설정하면 &lt;b&gt;폼 로딩 시 렉&lt;/b&gt;이 생기거나 &lt;b&gt;UI가 멈추는 현상&lt;/b&gt;이 발생할 수 있습니다.&lt;br /&gt;&lt;br /&gt;이 글에서는 &lt;b&gt;지연 로딩(Delayed Binding)&lt;/b&gt;으로 GridView를 빠르게 보여주고, 데이터는 백그라운드에서 로딩하는 방법을 소개합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 1. 왜 DataSource를 바로 바인딩하면 느려질까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GridControl은 &lt;code&gt;DataSource&lt;/code&gt;를 설정하는 순간 데이터를 분석하고 렌더링을 시작합니다.&lt;br /&gt;데이터가 많을수록 로딩 시간이 길어지며, 그 사이 UI가 멈추게 됩니다.&lt;br /&gt;&amp;rarr; 이 현상은 특히 WinForms에서 &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;✅ 2. Task.Run으로 백그라운드에서 데이터 로딩&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폼은 먼저 뜨고, 데이터는 백그라운드에서 로딩한 후 GridView에 바인딩하는 방식이 사용자 경험(UX)을 훨씬 개선시킵니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;
private async void MainForm_Load(object sender, EventArgs e)
{
    gridView.BeginUpdate();
    gridControl.DataSource = null;
    gridView.EndUpdate();

    loadingLabel.Visible = true; // &quot;로딩 중...&quot; 표시

    var data = await Task.Run(() =&amp;gt; GetDataFromDatabase());

    gridControl.DataSource = data;
    loadingLabel.Visible = false;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;code&gt;GetDataFromDatabase()&lt;/code&gt;는 시간이 오래 걸리는 DB 쿼리 또는 리스트 생성 함수입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 3. 로딩 중 표시 UI 간단 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폼에 &lt;code&gt;Label&lt;/code&gt; 또는 &lt;code&gt;ProgressPanel&lt;/code&gt; 등을 배치하여 &lt;b&gt;로딩 중&lt;/b&gt;임을 사용자에게 안내하세요.&lt;/p&gt;
&lt;pre class=&quot;arcade&quot;&gt;&lt;code&gt;
// 로딩 텍스트 설정
loadingLabel.Text = &quot;데이터 로딩 중입니다...&quot;;
loadingLabel.Visible = true;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; DevExpress라면 &lt;code&gt;SplashScreenManager&lt;/code&gt;도 좋은 대안입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 4. BeginUpdate / EndUpdate 반드시 사용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GridView 바인딩 시에도 &lt;code&gt;BeginUpdate()&lt;/code&gt;, &lt;code&gt;EndUpdate()&lt;/code&gt;를 사용하면 불필요한 렌더링을 막고 성능이 향상됩니다.&lt;/p&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;
gridView.BeginUpdate();
gridControl.DataSource = data;
gridView.EndUpdate();
&lt;/code&gt;&lt;/pre&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;폼 로드시 GridControl의 &lt;b&gt;DataSource = null&lt;/b&gt;로 초기화&lt;/li&gt;
&lt;li&gt;데이터는 &lt;b&gt;Task.Run&lt;/b&gt;으로 백그라운드에서 가져오기&lt;/li&gt;
&lt;li&gt;로딩 중임을 알려주는 UI 요소 표시&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BeginUpdate / EndUpdate&lt;/b&gt;로 렌더링 성능 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 방법을 적용하면 대용량 데이터를 바인딩해도 &lt;b&gt;화면 멈춤 없이 자연스럽게 로딩&lt;/b&gt;할 수 있습니다.&lt;br /&gt;사용자 경험도 좋아지고, 개발자도 속이 편해지는 구조입니다  &lt;br /&gt;&lt;br /&gt;도움이 되셨다면 &lt;b&gt;공감 / 댓글&lt;/b&gt; 부탁드립니다!&lt;/p&gt;
&lt;!-- 태그 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;!-- #DevExpress #GridControl #GridView #DataSource #지연로딩 #Task #WinForms #속도최적화 #렌더링최적화 #C# --&gt;</description>
      <category>프로그래밍/C#</category>
      <category>C#</category>
      <category>DataSource</category>
      <category>DevExpress</category>
      <category>gridcontrol</category>
      <category>gridview</category>
      <category>task</category>
      <category>winforms</category>
      <category>렌더링최적화</category>
      <category>속도최적화</category>
      <category>지연로딩</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/170</guid>
      <comments>https://qratedev.tistory.com/170#entry170comment</comments>
      <pubDate>Mon, 24 Mar 2025 13:16:50 +0900</pubDate>
    </item>
    <item>
      <title>[C#] DevExpress WinForms GridView 속도 개선 팁 &amp;ndash; 렌더링 최적화 &amp;amp; 클릭 지연 해결</title>
      <link>https://qratedev.tistory.com/169</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[WinForms] DevExpress GridView 속도 개선 팁 – 렌더링 최적화 &amp; 클릭 지연 해결&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
DevExpress의 &lt;strong&gt;GridView&lt;/strong&gt;는 강력한 기능을 제공하지만,  
데이터가 많아지면 &lt;strong&gt;속도 저하&lt;/strong&gt;나 &lt;strong&gt;렌더링 지연&lt;/strong&gt;,  
&lt;strong&gt;Row 클릭 시 딜레이&lt;/strong&gt; 같은 문제가 발생할 수 있습니다.&lt;br&gt;&lt;br&gt;

이 글에서는 실무에서 직접 적용했던 &lt;strong&gt;GridView 성능 최적화 팁&lt;/strong&gt;을  
구체적인 코드와 함께 소개하겠습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 1. BeginUpdate / EndUpdate로 렌더링 최소화&lt;/h2&gt;

&lt;p&gt;
여러 UI 변경을 한꺼번에 적용할 때는 반드시 &lt;code&gt;BeginUpdate()&lt;/code&gt;와 &lt;code&gt;EndUpdate()&lt;/code&gt;로 감싸서  
&lt;strong&gt;중간 렌더링을 막아야&lt;/strong&gt; 성능이 좋아집니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
gridView.BeginUpdate();
try
{
    gridControl.DataSource = GetData(); // 데이터 바인딩
}
finally
{
    gridView.EndUpdate();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;strong&gt;주의:&lt;/strong&gt; &lt;code&gt;EndUpdate()&lt;/code&gt;는 &lt;code&gt;finally&lt;/code&gt; 블록에서 반드시 호출하세요.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 2. RowCellClick 안에서 데이터 접근 최소화&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;RowCellClick&lt;/code&gt; 또는 &lt;code&gt;FocusedRowChanged&lt;/code&gt; 이벤트에서  
&lt;code&gt;GetRowCellValue&lt;/code&gt;를 반복 호출하면 성능이 저하될 수 있습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 성능 저하 예시
var val1 = gridView.GetRowCellValue(e.RowHandle, &quot;ColumnA&quot;);
var val2 = gridView.GetRowCellValue(e.RowHandle, &quot;ColumnB&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ &lt;strong&gt;개선 방법:&lt;/strong&gt; &lt;code&gt;GetRow&lt;/code&gt;로 한 번에 캐스팅한 후 필드 접근&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 최적화 예시
var row = gridView.GetRow(e.RowHandle) as MyModel;
if (row != null)
{
    var val1 = row.ColumnA;
    var val2 = row.ColumnB;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 특히 Row 클릭 시 팝업을 띄우거나 쿼리를 호출한다면 &lt;strong&gt;비동기 처리(Task.Run)&lt;/strong&gt;도 고려하세요.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 3. Column 정렬 &amp; 필터 성능 최적화&lt;/h2&gt;

&lt;p&gt;
컬럼 정렬이나 필터 기능이 많을수록 렌더링이 느려질 수 있습니다.&lt;br&gt;
&lt;strong&gt;필요 없는 컬럼은 AllowSort, AllowFilter를 꺼주세요.&lt;/strong&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
gridView.Columns[&quot;ColumnA&quot;].OptionsColumn.AllowSort = DefaultBoolean.False;
gridView.Columns[&quot;ColumnA&quot;].OptionsFilter.AllowFilter = false;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 정렬/필터가 꼭 필요한 컬럼만 켜놓는 것이 성능에 좋습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 4. AutoWidth, BestFitColumns 피하기&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;BestFitColumns()&lt;/code&gt;는 모든 셀의 크기를 측정하기 때문에  
&lt;strong&gt;데이터가 많을 경우 매우 느려집니다.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;→ 대안: 화면 너비 기준으로 컬럼 크기를 수동으로 설정하거나, 최소한 일부 컬럼만 BestFit&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 느려질 수 있는 코드
gridView.BestFitColumns(); 

// 대안
gridView.Columns[&quot;Name&quot;].BestFit();
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 5. 실시간 이벤트 남발 방지&lt;/h2&gt;

&lt;p&gt;
&lt;code&gt;CellValueChanged&lt;/code&gt;나 &lt;code&gt;RowChanged&lt;/code&gt; 이벤트에서  
매번 디비 호출, 로직 실행은 렌더링에 영향을 줄 수 있습니다.
&lt;/p&gt;

&lt;p&gt;→ 최소한 &lt;strong&gt;값이 실제로 변경된 경우에만 동작&lt;/strong&gt;하도록 처리&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
private void gridView_CellValueChanged(object sender, CellValueChangedEventArgs e)
{
    var newValue = e.Value?.ToString();
    var oldValue = gridView.GetRowCellValue(e.RowHandle, e.Column.FieldName)?.ToString();

    if (newValue != oldValue)
    {
        // 변경된 경우에만 처리
        UpdateToDatabase(newValue);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
DevExpress GridView는 매우 강력하지만, &lt;strong&gt;속도 최적화는 반드시 필요&lt;/strong&gt;합니다.&lt;br&gt;
위의 팁들을 프로젝트에 적용하면 &lt;strong&gt;화면 전환 속도&lt;/strong&gt;, &lt;strong&gt;클릭 반응성&lt;/strong&gt;, &lt;strong&gt;스크롤 성능&lt;/strong&gt;이 눈에 띄게 향상됩니다.&lt;br&gt;&lt;br&gt;

앞으로도 WinForms + DevExpress 실무 팁을 계속 공유할 예정이니,  
도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #WinForms #DevExpress #GridView #속도개선 #성능최적화 #C# #그리드뷰성능 #BeginUpdate #렌더링지연 #RowClick --&gt;</description>
      <category>프로그래밍/C#</category>
      <category>beginupdate</category>
      <category>C#</category>
      <category>DevExpress</category>
      <category>gridview</category>
      <category>rowclick</category>
      <category>winforms</category>
      <category>그리드뷰성능</category>
      <category>렌더링지연</category>
      <category>성능최적화</category>
      <category>속도개선</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/169</guid>
      <comments>https://qratedev.tistory.com/169#entry169comment</comments>
      <pubDate>Mon, 24 Mar 2025 12:26:11 +0900</pubDate>
    </item>
    <item>
      <title>[C#] Singleton, Scoped, Transient 차이점 &amp;ndash; DI Container 생명주기 완전 정리</title>
      <link>https://qratedev.tistory.com/168</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[C#] Singleton, Scoped, Transient 차이점 – DI Container 생명주기 완전 정리&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
C#에서 &lt;strong&gt;의존성 주입(Dependency Injection)&lt;/strong&gt;을 사용할 때,  
DI Container에 등록할 수 있는 &lt;code&gt;Singleton&lt;/code&gt;, &lt;code&gt;Scoped&lt;/code&gt;, &lt;code&gt;Transient&lt;/code&gt;는 각기 다른 생명주기를 가지고 있습니다.&lt;br&gt;&lt;br&gt;

실무에서 자주 쓰이는 이 3가지 생명주기의 &lt;strong&gt;차이점&lt;/strong&gt;과 &lt;strong&gt;사용 시 주의할 점&lt;/strong&gt;,  
그리고 &lt;strong&gt;예제를 통한 설명&lt;/strong&gt;을 함께 정리해보겠습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  1. Singleton – 앱 전체에서 단 하나&lt;/h2&gt;

&lt;p&gt;
Singleton으로 등록된 서비스는 &lt;strong&gt;애플리케이션 실행 동안 딱 1개 인스턴스&lt;/strong&gt;만 생성되어, 모든 곳에서 공유됩니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 등록 방법
services.AddSingleton&amp;lt;IMyService, MyService&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;처음 요청 시 1회 생성 → 이후 모든 요청에서 동일한 인스턴스 반환&lt;/li&gt;
  &lt;li&gt;상태를 유지해야 하는 캐시, 설정, Logger 등에 적합&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;주의:&lt;/strong&gt; 상태 공유 때문에 &lt;code&gt;Thread-Safe&lt;/code&gt;하게 설계되어야 합니다.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  2. Scoped – 요청(Request)당 하나&lt;/h2&gt;

&lt;p&gt;
Scoped로 등록된 서비스는 &lt;strong&gt;HTTP 요청마다 새 인스턴스&lt;/strong&gt;가 생성됩니다.&lt;br&gt;
ASP.NET Core에서는 &lt;strong&gt;컨트롤러 단위로 공유&lt;/strong&gt;되며, 동일 요청 안에서는 하나의 인스턴스가 사용됩니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 등록 방법
services.AddScoped&amp;lt;IMyService, MyService&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;웹 요청마다 새로운 인스턴스 생성&lt;/li&gt;
  &lt;li&gt;DBContext, 사용자 요청 데이터 처리에 적합&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;주의:&lt;/strong&gt; 콘솔 앱이나 WinForms에서는 별도 Scope 관리가 필요합니다.&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;⚡ 3. Transient – 요청마다 새로 생성&lt;/h2&gt;

&lt;p&gt;
Transient는 &lt;strong&gt;요청될 때마다 항상 새로운 인스턴스&lt;/strong&gt;를 생성합니다.&lt;br&gt;
의존 객체까지 전부 새로 만들어지기 때문에 &lt;strong&gt;가볍고 독립적인 서비스&lt;/strong&gt;에 적합합니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 등록 방법
services.AddTransient&amp;lt;IMyService, MyService&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;요청마다 새 인스턴스 생성 (심지어 같은 요청에서도 여러 번 생성 가능)&lt;/li&gt;
  &lt;li&gt;상태를 가지지 않는 Helper 클래스, 계산기, 포맷터 등에 적합&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;h2&gt;  생명주기 비교 표&lt;/h2&gt;

&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
  &lt;thead&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;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Singleton&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;앱 전체에서 1개&lt;/td&gt;
      &lt;td&gt;설정, 캐시, 공통 서비스&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Scoped&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;요청(Request)당 1개&lt;/td&gt;
      &lt;td&gt;DBContext, 사용자 세션&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;strong&gt;Transient&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;요청마다 새로&lt;/td&gt;
      &lt;td&gt;Helper, Utility, Stateless 서비스&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;hr&gt;

&lt;h2&gt;  실무 팁 – 언제 어떤 생명주기를 써야 할까?&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Singleton&lt;/strong&gt; – 상태를 공유해도 문제가 없는 서비스 (예: 로깅, 캐시)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Scoped&lt;/strong&gt; – 요청 기반의 리소스를 다룰 때 (예: DbContext)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Transient&lt;/strong&gt; – 가벼운 서비스, 상태가 없는 도구성 클래스&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
잘못된 생명주기를 적용하면 &lt;strong&gt;의도하지 않은 상태 공유&lt;/strong&gt;나 &lt;strong&gt;메모리 낭비&lt;/strong&gt;가 발생할 수 있습니다.&lt;br&gt;
따라서 서비스의 &lt;strong&gt;역할과 범위&lt;/strong&gt;에 따라 생명주기를 신중하게 선택해야 합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리&lt;/h2&gt;

&lt;p&gt;
의존성 주입(DI)은 유지보수성과 테스트 용이성을 높여주는 핵심 기술입니다.&lt;br&gt;
그만큼 생명주기를 제대로 이해하고 사용하는 것이 중요합니다.&lt;br&gt;&lt;br&gt;

이 글이 도움이 되셨다면 &lt;strong&gt;공감 / 댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #C# #DI #의존성주입 #Singleton #Scoped #Transient #생명주기 #ASP.NET #C#실무팁 --&gt;</description>
      <category>프로그래밍/C#</category>
      <category>ASP.NET</category>
      <category>C#</category>
      <category>c#실무팁</category>
      <category>Di</category>
      <category>scoped</category>
      <category>singleton</category>
      <category>transient</category>
      <category>생명주기</category>
      <category>의존성주입</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/168</guid>
      <comments>https://qratedev.tistory.com/168#entry168comment</comments>
      <pubDate>Mon, 24 Mar 2025 11:00:23 +0900</pubDate>
    </item>
    <item>
      <title>[C#] Singleton 패턴 잘못 쓰면 발생하는 문제 &amp;ndash; 메모리 누수 &amp;amp; DI 문제</title>
      <link>https://qratedev.tistory.com/167</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[C#] Singleton 패턴 잘못 쓰면 발생하는 문제 – 메모리 누수 &amp; DI 문제&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
C#에서 &lt;strong&gt;Singleton 패턴&lt;/strong&gt;은 전역 인스턴스를 하나만 유지한다는 점에서 자주 사용됩니다.  
하지만 잘못된 싱글톤 사용은 &lt;strong&gt;메모리 누수&lt;/strong&gt;, &lt;strong&gt;테스트 어려움&lt;/strong&gt;, &lt;strong&gt;의존성 주입(DI) 충돌&lt;/strong&gt; 등의 문제를 발생시킬 수 있습니다.&lt;br&gt;&lt;br&gt;
이 글에서는 Singleton 패턴의 기본 구조와 함께 &lt;strong&gt;실무에서 문제가 되는 사용 예&lt;/strong&gt;, 그리고 &lt;strong&gt;올바른 구현 방법&lt;/strong&gt;을 소개하겠습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ Singleton 패턴 기본 구조&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 기본 싱글톤 구현 (Lazy + Thread-safe)
public sealed class MyService
{
    private static readonly Lazy&amp;lt;MyService&amp;gt; instance =
        new Lazy&amp;lt;MyService&amp;gt;(() =&amp;gt; new MyService());

    public static MyService Instance =&amp;gt; instance.Value;

    private MyService()
    {
        // 생성자
    }

    public void DoSomething()
    {
        Console.WriteLine(&quot;작업 실행&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
이 구조는 실무에서 가장 많이 쓰이는 &lt;strong&gt;Lazy + Thread-safe&lt;/strong&gt; 패턴입니다.&lt;br&gt;
하지만 아래와 같은 문제들을 유발할 수 있습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;⚠️ 문제 1 – 테스트 코드 작성 어려움&lt;/h2&gt;

&lt;p&gt;
싱글톤 인스턴스는 전역 상태를 가지기 때문에, &lt;strong&gt;단위 테스트에서 격리(Isolation)된 테스트 작성이 어렵습니다.&lt;/strong&gt;&lt;br&gt;
Mocking이 어렵고, 테스트 간 상태 공유로 인해 예기치 않은 결과가 발생할 수 있습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 다음 테스트는 상태 공유 문제를 일으킬 수 있음
MyService.Instance.DoSomething(); // 이전 테스트의 상태가 남아있음
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;⚠️ 문제 2 – DI(Dependency Injection)와 충돌&lt;/h2&gt;

&lt;p&gt;
최근에는 &lt;strong&gt;의존성 주입(Dependency Injection)&lt;/strong&gt;을 활용하는 경우가 많은데,  
이 때 Singleton 패턴은 &lt;strong&gt;DI 컨테이너가 객체 생명주기를 관리하는 방식과 충돌&lt;/strong&gt;할 수 있습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// DI Container에서 관리되는 객체 예시
services.AddSingleton&amp;lt;IMyService, MyService&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
DI 컨테이너를 사용한다면 굳이 수동으로 Singleton 패턴을 구현할 필요 없이  
컨테이너에게 &lt;code&gt;Singleton&lt;/code&gt; 생명주기를 맡기는 게 더 안전하고 유연합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;⚠️ 문제 3 – 메모리 누수&lt;/h2&gt;

&lt;p&gt;
GC(가비지 컬렉터)는 더 이상 참조되지 않는 객체를 정리하지만,  
Singleton은 &lt;strong&gt;앱 종료 시까지 메모리에 유지&lt;/strong&gt;되기 때문에  
&lt;strong&gt;불필요한 리소스가 계속 메모리에 남아 메모리 누수처럼 보일 수 있습니다.&lt;/strong&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 싱글톤 내부에서 IDisposable 리소스를 직접 관리하면 누수 위험
private SqlConnection conn = new SqlConnection(...);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
→ 이럴 땐 &lt;strong&gt;IDisposable을 구현하지 말고&lt;/strong&gt;, 외부에서 의존성 주입 받는 구조로 개선해야 합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 해결 방법 – DI와 함께 쓰는 Singleton&lt;/h2&gt;

&lt;p&gt;
.NET Core 이상에서는 &lt;code&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt;을 통해  
싱글톤 생명주기를 컨트롤 할 수 있습니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// Startup.cs 또는 Program.cs에서 등록
services.AddSingleton&amp;lt;IMyService, MyService&amp;gt;();

// 생성자 주입으로 사용
public class MyController
{
    private readonly IMyService myService;

    public MyController(IMyService myService)
    {
        this.myService = myService;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;
이처럼 &lt;strong&gt;DI Container를 활용한 Singleton 등록 방식&lt;/strong&gt;이  
테스트 코드 작성, 생명주기 관리, 메모리 안정성 측면에서 훨씬 유리합니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;  마무리 요약&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;전통적인 Singleton 패턴은 간단하지만 &lt;strong&gt;테스트/확장/DI 측면에서 단점&lt;/strong&gt;이 많음&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;의존성 주입&lt;/strong&gt;을 활용해 Singleton을 안전하게 구현하는 것이 권장됨&lt;/li&gt;
  &lt;li&gt;싱글톤 내부에 &lt;strong&gt;리소스를 직접 소유하지 말고&lt;/strong&gt;, 외부에서 주입받는 구조가 이상적&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
실무에서는 항상 &lt;strong&gt;유지보수성과 테스트 가능성&lt;/strong&gt;을 고려한 구조 설계가 중요합니다.&lt;br&gt;
이 글이 도움이 되셨다면 &lt;strong&gt;공감/댓글&lt;/strong&gt; 부탁드려요  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #C샵 #C# #디자인패턴 #Singleton #싱글톤 #메모리누수 #DI #의존성주입 #C#실무팁 #C#패턴 --&gt;</description>
      <category>프로그래밍/C#</category>
      <category>C#</category>
      <category>c#실무팁</category>
      <category>c#패턴</category>
      <category>C샵</category>
      <category>Di</category>
      <category>singleton</category>
      <category>디자인패턴</category>
      <category>메모리누수</category>
      <category>싱글톤</category>
      <category>의존성주입</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/167</guid>
      <comments>https://qratedev.tistory.com/167#entry167comment</comments>
      <pubDate>Mon, 24 Mar 2025 08:25:05 +0900</pubDate>
    </item>
    <item>
      <title>[C#] 디자인 패턴 - 실무에서 가장 많이 쓰는 디자인 패턴 3가지 정리 (Singleton, Factory, Command)</title>
      <link>https://qratedev.tistory.com/166</link>
      <description>&lt;!-- 제목 --&gt;
&lt;h1&gt;[C# 디자인 패턴] 실무에서 가장 많이 쓰는 디자인 패턴 3가지 정리&lt;/h1&gt;

&lt;!-- 본문 --&gt;
&lt;p&gt;
C# 개발을 하다 보면 다양한 디자인 패턴을 접하게 됩니다. 하지만 실무에서는 자주 쓰는 몇 가지 패턴만 집중적으로 활용되곤 합니다.&lt;br&gt;&lt;br&gt;
이 글에서는 C# 실무에서 가장 자주 쓰이는 &lt;strong&gt;디자인 패턴 3가지&lt;/strong&gt;를 소개하고, &lt;strong&gt;구현 코드 예제&lt;/strong&gt;와 함께 어떤 상황에서 쓰면 좋은지 설명드리겠습니다.
&lt;/p&gt;

&lt;hr&gt;

&lt;h2&gt;1. 싱글톤 패턴 (Singleton Pattern)&lt;/h2&gt;
&lt;p&gt;
싱글톤 패턴은 하나의 인스턴스만 생성되도록 제한하고, 전역 접근이 가능하게 만드는 디자인 패턴입니다.&lt;br&gt;
주로 설정 클래스, DB 연결 클래스 등에 사용됩니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// Thread-safe Singleton 예제
public sealed class ConfigManager
{
    private static readonly Lazy&amp;lt;ConfigManager&amp;gt; instance =
        new Lazy&amp;lt;ConfigManager&amp;gt;(() =&amp;gt; new ConfigManager());

    public static ConfigManager Instance =&amp;gt; instance.Value;

    private ConfigManager()
    {
        // 초기 설정 로딩
    }

    public string GetValue(string key)
    {
        // 설정 값 반환
        return &quot;설정값&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;사용 예:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
string dbConnection = ConfigManager.Instance.GetValue(&quot;DbConnection&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;2. 팩토리 패턴 (Factory Pattern)&lt;/h2&gt;
&lt;p&gt;
팩토리 패턴은 객체 생성 로직을 별도의 팩토리 클래스나 메서드로 분리하는 패턴입니다.&lt;br&gt;
복잡한 생성 과정을 캡슐화하고, 의존성을 줄이는 데 유리합니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 인터페이스
public interface INotification
{
    void Send(string message);
}

// 구현 클래스
public class EmailNotification : INotification
{
    public void Send(string message)
    {
        Console.WriteLine($&quot;Email: {message}&quot;);
    }
}

// 팩토리
public static class NotificationFactory
{
    public static INotification Create(string type)
    {
        return type switch
        {
            &quot;email&quot; =&amp;gt; new EmailNotification(),
            _ =&amp;gt; throw new ArgumentException(&quot;Unknown type&quot;),
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;사용 예:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
var notifier = NotificationFactory.Create(&quot;email&quot;);
notifier.Send(&quot;Hello from factory!&quot;);
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;3. 커맨드 패턴 (Command Pattern)&lt;/h2&gt;
&lt;p&gt;
커맨드 패턴은 요청을 캡슐화하여 실행 취소, 재실행, 큐잉 등을 유연하게 처리할 수 있게 합니다.&lt;br&gt;
주로 UI 버튼 이벤트 처리, Undo/Redo 기능 구현에 많이 사용됩니다.
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
// 커맨드 인터페이스
public interface ICommand
{
    void Execute();
}

// 구현 클래스
public class SaveCommand : ICommand
{
    public void Execute()
    {
        Console.WriteLine(&quot;문서를 저장했습니다.&quot;);
    }
}

// 인보커
public class Button
{
    private ICommand command;
    public Button(ICommand command)
    {
        this.command = command;
    }

    public void Click()
    {
        command.Execute();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;사용 예:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;
var save = new SaveCommand();
var saveButton = new Button(save);
saveButton.Click();
&lt;/code&gt;&lt;/pre&gt;

&lt;hr&gt;

&lt;h2&gt;✅ 마무리&lt;/h2&gt;
&lt;p&gt;
위 3가지 패턴은 C# 실무에서 매우 자주 사용되며, 유지보수성과 확장성을 높여줍니다.&lt;br&gt;
이 외에도 전략 패턴, 옵저버 패턴 등도 실무에서 유용하게 쓰이지만, 우선은 위 세 가지부터 익혀두면 대부분의 프로젝트에서 큰 도움이 됩니다.
&lt;/p&gt;

&lt;p&gt;
앞으로도 C# 실무에 도움이 되는 글들을 계속해서 올릴 예정입니다. 도움이 되셨다면 &lt;strong&gt;공감/댓글&lt;/strong&gt; 부탁드립니다  
&lt;/p&gt;

&lt;!-- 태그 --&gt;
&lt;!-- #C샵 #디자인패턴 #C#디자인패턴 #Singleton #Factory #Command패턴 #C#패턴 #개발자팁 #코딩패턴 --&gt;</description>
      <category>프로그래밍/C#</category>
      <category>C#</category>
      <category>c#디자인패턴</category>
      <category>c#코딩</category>
      <category>command패턴</category>
      <category>C샵</category>
      <category>factory</category>
      <category>singleton</category>
      <category>개발자팁</category>
      <category>디자인패턴</category>
      <category>실무팁</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/166</guid>
      <comments>https://qratedev.tistory.com/166#entry166comment</comments>
      <pubDate>Fri, 21 Mar 2025 15:24:06 +0900</pubDate>
    </item>
    <item>
      <title>[python] FastAPI에서 async/await으로 비동기 API 만들기 - 느린 작업도 빠르게 처리하기</title>
      <link>https://qratedev.tistory.com/165</link>
      <description>&lt;h1&gt;FastAPI에서 async/await으로 비동기 API 만들기 - 느린 작업도 빠르게 처리하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 Python의 &lt;code&gt;async/await&lt;/code&gt; 구문을 완벽하게 지원하는 웹 프레임워크입니다.&lt;br /&gt;이를 통해 느린 작업(예: 파일 처리, 외부 API 호출, 데이터베이스 쿼리 등)도 &lt;b&gt;효율적이고 빠르게 처리&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 비동기 함수란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;async def&lt;/code&gt;로 선언된 함수는 비동기 함수이며, &lt;code&gt;await&lt;/code&gt;를 통해 다른 작업이 완료될 때까지 기다리는 동안 &lt;b&gt;블로킹 없이 다른 요청을 처리&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 하나의 요청이 처리되는 동안 서버가 멈추지 않고 &lt;b&gt;동시에 여러 요청을 병렬로 처리&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ FastAPI 비동기 예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;느린 작업(예: 3초 대기)을 시뮬레이션한 API를 만들어봅니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get(&quot;/sync-task&quot;)
def sync_task():
    import time
    time.sleep(3)  # 동기 처리: 서버가 멈춤
    return {&quot;message&quot;: &quot;동기 작업 완료&quot;}

@app.get(&quot;/async-task&quot;)
async def async_task():
    await asyncio.sleep(3)  # 비동기 처리: 다른 요청 병렬 처리 가능
    return {&quot;message&quot;: &quot;비동기 작업 완료&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  주요 차이점&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;/sync-task&lt;/th&gt;
&lt;th&gt;/async-task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;서버 응답 대기&lt;/td&gt;
&lt;td&gt;3초 동안 멈춤&lt;/td&gt;
&lt;td&gt;다른 요청 동시에 처리 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;async/await 사용&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;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 테스트 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 실행:&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;uvicorn main:app --reload&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 URL:&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;http://127.0.0.1:8000/sync-task&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://127.0.0.1:8000/sync-task&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://127.0.0.1:8000/async-task&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://127.0.0.1:8000/async-task&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- 여기 비동기 호출 테스트 스샷 추가 가능 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postman이나 Swagger UI(&lt;a href=&quot;http://127.0.0.1:8000/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;/docs&lt;/a&gt;)에서 동시에 여러 요청을 보내보면, &lt;b&gt;비동기 엔드포인트는 지연 없이 처리&lt;/b&gt;되는 걸 확인할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 언제 async/await을 써야 할까?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;⏳ 외부 API 호출&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 data-ke-size=&quot;size16&quot;&gt;즉, CPU 연산이 아닌 &lt;b&gt;I/O 바운드 작업&lt;/b&gt;에서는 비동기를 사용하면 서버 응답성과 처리량이 눈에 띄게 향상됩니다.&lt;/p&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;code&gt;async def&lt;/code&gt;로 선언된 비동기 함수는 동시에 여러 요청을 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;await&lt;/code&gt;는 느린 작업이 완료될 때까지 기다리며, 그 사이 다른 요청이 처리됩니다.&lt;/li&gt;
&lt;li&gt;FastAPI는 Python의 비동기 기능을 적극 활용해 &lt;b&gt;높은 성능의 API 서버&lt;/b&gt;를 만들 수 있도록 도와줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI의 async/await을 적절히 활용하면, 느린 작업도 빠르게 처리되는 고성능 API를 구축할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;※ 본 예제는 Python 3.12 + FastAPI 최신 버전에서 테스트되었습니다.&lt;/i&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>api서버</category>
      <category>async await</category>
      <category>FastAPI</category>
      <category>fastapi async</category>
      <category>Python</category>
      <category>REST API</category>
      <category>비동기</category>
      <category>비동기api</category>
      <category>비동기처리</category>
      <category>웹프레임워크</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/165</guid>
      <comments>https://qratedev.tistory.com/165#entry165comment</comments>
      <pubDate>Thu, 20 Mar 2025 18:49:28 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI에서 POST 요청 처리하기 - 사용자 입력 데이터 받기 예제</title>
      <link>https://qratedev.tistory.com/164</link>
      <description>&lt;h1&gt;FastAPI에서 POST 요청 처리하기 - 사용자 입력 데이터 받기 예제&lt;/h1&gt;

&lt;p&gt;
FastAPI를 사용하면 &lt;strong&gt;간단한 문법&lt;/strong&gt;으로 REST API를 만들 수 있으며, &lt;code&gt;GET&lt;/code&gt; 요청뿐만 아니라 &lt;strong&gt;POST 요청&lt;/strong&gt;도 매우 쉽게 처리할 수 있습니다.&lt;br&gt;
이 글에서는 사용자 입력 데이터를 받아 처리하는 POST 요청 예제를 소개합니다.
&lt;/p&gt;

&lt;h2&gt;✅ 사용자 정보 등록 API 만들기&lt;/h2&gt;

&lt;p&gt;
POST 요청을 처리하려면 먼저 &lt;strong&gt;데이터 모델&lt;/strong&gt;을 정의해야 합니다.&lt;br&gt;
FastAPI는 &lt;code&gt;pydantic&lt;/code&gt;을 활용하여 입력 데이터를 자동으로 검증해 줍니다.
&lt;/p&gt;

&lt;h3&gt;  models.py&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
    email: str
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;  main.py&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from fastapi import FastAPI
from models import User

app = FastAPI()

@app.post(&quot;/users/&quot;)
def create_user(user: User):
    return {
        &quot;message&quot;: f&quot;{user.name}님의 정보가 등록되었습니다.&quot;,
        &quot;data&quot;: user
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;✅ API 테스트 방법&lt;/h2&gt;

&lt;h3&gt;1. Swagger UI 이용&lt;/h3&gt;

&lt;p&gt;
FastAPI는 자동으로 문서화된 UI를 제공합니다.&lt;br&gt;
다음 주소로 접속하면 브라우저에서 직접 POST 요청을 보낼 수 있습니다:
&lt;/p&gt;

&lt;p&gt;
  &lt;a href=&quot;http://127.0.0.1:8000/docs&quot; target=&quot;_blank&quot;&gt;http://127.0.0.1:8000/docs&lt;/a&gt;
&lt;/p&gt;

&lt;!-- 여기에 Swagger 테스트 화면 스샷 삽입 --&gt;

&lt;h3&gt;2. curl 명령어 사용&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -X 'POST' 'http://127.0.0.1:8000/users/' \
     -H 'Content-Type: application/json' \
     -d '{&quot;name&quot;: &quot;철수&quot;, &quot;age&quot;: 30, &quot;email&quot;: &quot;chulsoo@example.com&quot;}'
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;✅ 응답 예시&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;{
  &quot;message&quot;: &quot;철수님의 정보가 등록되었습니다.&quot;,
  &quot;data&quot;: {
    &quot;name&quot;: &quot;철수&quot;,
    &quot;age&quot;: 30,
    &quot;email&quot;: &quot;chulsoo@example.com&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;✅ 핵심 정리&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;@app.post()&lt;/code&gt; 데코레이터를 사용해 POST 엔드포인트를 생성합니다.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;pydantic.BaseModel&lt;/code&gt;을 상속한 클래스에서 필드 타입 검증을 자동으로 처리합니다.&lt;/li&gt;
  &lt;li&gt;Swagger UI 덕분에 API 테스트와 디버깅이 매우 편리합니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
FastAPI는 복잡한 로직 없이도 API 요청 처리, 입력 검증, 문서화까지 모두 자동으로 해결해 줍니다.&lt;br&gt;
간단한 코드로 강력한 백엔드 API를 만들 수 있는 점이 가장 큰 장점입니다.
&lt;/p&gt;

&lt;hr&gt;
&lt;p&gt;&lt;em&gt;※ 본 글의 예제는 Python 3.12 및 FastAPI 최신 버전 기준으로 작성되었습니다.&lt;/em&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>api개발</category>
      <category>FastAPI</category>
      <category>post 요청</category>
      <category>Pydantic</category>
      <category>Python</category>
      <category>python웹프레임워크</category>
      <category>REST API</category>
      <category>SWAGGER</category>
      <category>데이터검증</category>
      <category>파이썬 API</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/164</guid>
      <comments>https://qratedev.tistory.com/164#entry164comment</comments>
      <pubDate>Thu, 20 Mar 2025 17:51:55 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI로 빠르고 간단한 파이썬 API 서버 만들기 - 설치부터 기본 예제까지</title>
      <link>https://qratedev.tistory.com/163</link>
      <description>&lt;h1&gt;FastAPI로 빠르고 간단한 파이썬 API 서버 만들기 - 설치부터 기본 예제까지&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python으로 웹 API를 개발할 때 가장 많이 사용되는 프레임워크는 &lt;b&gt;Flask&lt;/b&gt;와 &lt;b&gt;Django&lt;/b&gt;입니다.&lt;br /&gt;하지만 최근에는 &lt;b&gt;FastAPI&lt;/b&gt;가 성능과 편의성 면에서 강력한 대안으로 주목받고 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ FastAPI란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 다음과 같은 특징을 가진 최신 Python 웹 프레임워크입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;빠른 속도&lt;/b&gt; &amp;ndash; Flask보다 2~3배 빠르고, Node.js보다도 빠름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비동기 지원&lt;/b&gt; &amp;ndash; async/await 기반으로 높은 성능 구현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동 문서화&lt;/b&gt; &amp;ndash; Swagger UI, ReDoc 자동 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간단한 코드&lt;/b&gt; &amp;ndash; Flask보다 더 직관적인 사용법 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;대규모 API 서버 구축&lt;/b&gt;이나 &lt;b&gt;고성능 비동기 처리&lt;/b&gt;가 필요한 프로젝트에 적합합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ FastAPI 설치하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pip 명령어로 FastAPI와 실행 서버인 uvicorn을 설치합니다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install fastapi uvicorn&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ FastAPI 기본 예제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;main.py&lt;/code&gt; 파일을 만들고 다음 코드를 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;from fastapi import FastAPI

app = FastAPI()

@app.get(&quot;/&quot;)
def read_root():
    return {&quot;message&quot;: &quot;Hello, FastAPI!&quot;}

@app.get(&quot;/items/{item_id}&quot;)
def read_item(item_id: int, q: str = None):
    return {&quot;item_id&quot;: item_id, &quot;query&quot;: q}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✔ 코드 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;FastAPI()&lt;/code&gt;로 앱 인스턴스를 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@app.get(&quot;/&quot;)&lt;/code&gt;: 루트 경로에 GET 요청 처리&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@app.get(&quot;/items/{item_id}&quot;)&lt;/code&gt;: URL 파라미터와 쿼리스트링 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ FastAPI 서버 실행&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어를 터미널에서 실행합니다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;uvicorn main:app --reload&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;&lt;code&gt;--reload&lt;/code&gt; 옵션은 코드 변경 시 서버 자동 재시작&lt;/li&gt;
&lt;li&gt;접속 주소: &lt;a href=&quot;http://127.0.0.1:8000&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://127.0.0.1:8000&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;예시 요청: &lt;a href=&quot;http://127.0.0.1:8000/items/42?q=fastapi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;/items/42?q=fastapi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;item_id&quot;: 42,
  &quot;query&quot;: &quot;fastapi&quot;
}&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;FastAPI는 OpenAPI 기반의 &lt;b&gt;자동 API 문서&lt;/b&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;b&gt;Swagger UI:&lt;/b&gt; &lt;a href=&quot;http://127.0.0.1:8000/docs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;/docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ReDoc:&lt;/b&gt; &lt;a href=&quot;http://127.0.0.1:8000/redoc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;/redoc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;별도의 설정 없이 문서가 자동 생성되며, Swagger UI에서 API 요청 테스트도 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;563&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YOCVD/btsMQg2xmyg/utIYMdb82JcNlr2BVQDGfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YOCVD/btsMQg2xmyg/utIYMdb82JcNlr2BVQDGfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YOCVD/btsMQg2xmyg/utIYMdb82JcNlr2BVQDGfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYOCVD%2FbtsMQg2xmyg%2FutIYMdb82JcNlr2BVQDGfK%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;773&quot; height=&quot;563&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;563&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;!--   스크린샷 자리에 이미지 삽입하세요 --&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;b&gt;FastAPI&lt;/b&gt;는 간단한 문법과 빠른 성능을 갖춘 Python 기반의 API 프레임워크입니다.&lt;/li&gt;
&lt;li&gt;비동기 처리를 기본으로 지원하고, 자동 문서화 기능 덕분에 백엔드 개발 생산성이 크게 향상됩니다.&lt;/li&gt;
&lt;li&gt;설정이 간단하고 확장성이 뛰어나, 개인 프로젝트부터 실무 API 서버까지 널리 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python으로 REST API를 개발하고자 할 때, FastAPI는 꼭 한 번 써볼 만한 프레임워크입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;em&gt;※ 본 포스트는 Python 3.12 환경을 기준으로 작성되었습니다.&lt;/em&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>api서버</category>
      <category>FastAPI</category>
      <category>Python</category>
      <category>Redoc</category>
      <category>REST API</category>
      <category>SWAGGER</category>
      <category>uvicorn</category>
      <category>비동기</category>
      <category>웹개발</category>
      <category>파이썬</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/163</guid>
      <comments>https://qratedev.tistory.com/163#entry163comment</comments>
      <pubDate>Thu, 20 Mar 2025 12:25:03 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 로그 관리, loguru로 더 쉽게! 설정부터 파일 저장까지 정리</title>
      <link>https://qratedev.tistory.com/162</link>
      <description>&lt;h1&gt;파이썬 로그 관리, loguru로 더 쉽게! 설정부터 파일 저장까지 정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서 로그를 남기려면 &lt;code&gt;logging&lt;/code&gt; 모듈을 사용하지만, 설정이 복잡하고 불편하게 느껴질 수 있습니다.&lt;br /&gt;이럴 때 &lt;b&gt;간편한 설정과 강력한 기능&lt;/b&gt;을 제공하는 &lt;code&gt;loguru&lt;/code&gt; 라이브러리를 활용하면 로그 관리가 훨씬 쉬워집니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ loguru 설치 방법&lt;/h2&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install loguru&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 후 바로 사용할 수 있으며, 추가 설정 없이도 로그 출력이 가능합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 기본 사용법&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from loguru import logger

logger.info(&quot;이것은 정보 로그입니다.&quot;)
logger.warning(&quot;이것은 경고 로그입니다.&quot;)
logger.error(&quot;이것은 오류 로그입니다.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 예시:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;2025-02-19 12:00:00.000 | INFO     | __main__:1 - 이것은 정보 로그입니다.
2025-02-19 12:00:00.001 | WARNING  | __main__:2 - 이것은 경고 로그입니다.
2025-02-19 12:00:00.002 | ERROR    | __main__:3 - 이것은 오류 로그입니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 로그를 파일로 저장하기&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;logger.add(&quot;logfile.log&quot;, rotation=&quot;10 MB&quot;)  # 10MB 단위로 자동 분할
logger.info(&quot;파일에 저장되는 로그입니다.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용량이 초과되면 &lt;code&gt;logfile.log&lt;/code&gt;, &lt;code&gt;logfile.log.1&lt;/code&gt;, &lt;code&gt;logfile.log.2&lt;/code&gt;처럼 자동으로 파일이 분할 저장됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 로그 출력 형식 커스터마이징&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;logger.add(
    &quot;logfile.log&quot;,
    format=&quot;{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}&quot;,
    level=&quot;INFO&quot;
)

logger.debug(&quot;이 로그는 출력되지 않습니다.&quot;)
logger.info(&quot;이 로그는 출력됩니다.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;format&lt;/code&gt;을 지정해 출력 형식을 자유롭게 설정할 수 있고, &lt;code&gt;level&lt;/code&gt;로 로그 레벨 필터링도 가능합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 로그 보존 기간 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loguru는 오래된 로그를 자동으로 삭제할 수 있도록 &lt;code&gt;retention&lt;/code&gt; 설정을 지원합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;logger.add(
    &quot;runtime.log&quot;,
    rotation=&quot;1 day&quot;,      # 하루 단위로 분할
    retention=&quot;7 days&quot;     # 7일 이상 된 로그는 자동 삭제
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;retention&lt;/code&gt;에는 문자열(예: &quot;7 days&quot;, &quot;30 days&quot;) 또는 datetime 객체를 사용할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 로그 압축 저장 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그 파일이 분할될 때, 자동으로 압축해 저장할 수도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;logger.add(
    &quot;compressed_log.log&quot;,
    rotation=&quot;5 MB&quot;,
    retention=&quot;10 days&quot;,
    compression=&quot;zip&quot;  # 또는 'gz', 'bz2', 'xz'
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;압축 포맷은 &lt;code&gt;zip&lt;/code&gt;, &lt;code&gt;gz&lt;/code&gt;, &lt;code&gt;bz2&lt;/code&gt;, &lt;code&gt;xz&lt;/code&gt; 등을 지원하며, 로그 저장 공간을 절약할 수 있습니다.&lt;/p&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;b&gt;loguru&lt;/b&gt;는 설정이 간단하면서도 매우 강력한 로그 관리 기능을 제공합니다.&lt;/li&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;파이썬 프로젝트에서 로그 관리가 필요하다면 loguru를 도입해보세요.&lt;br /&gt;간결한 문법과 다양한 기능 덕분에 개발 효율이 확실히 올라갑니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;em&gt;※ 본 포스트는 Python 3.12 환경을 기준으로 작성되었습니다.&lt;/em&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>logging</category>
      <category>loguru</category>
      <category>Python</category>
      <category>로그</category>
      <category>로그라이브러리</category>
      <category>로그보존</category>
      <category>로그압축</category>
      <category>로그파일</category>
      <category>로깅</category>
      <category>파이썬</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/162</guid>
      <comments>https://qratedev.tistory.com/162#entry162comment</comments>
      <pubDate>Thu, 20 Mar 2025 10:00:38 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 데이터 검증을 쉽게 해주는 Pydantic 라이브러리 사용법</title>
      <link>https://qratedev.tistory.com/161</link>
      <description>&lt;h1&gt;파이썬 데이터 검증을 쉽게 해주는 Pydantic 라이브러리 사용법&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python으로 API를 다루거나 JSON 데이터를 처리하다 보면, 입력값을 검증하고 타입을 체크하는 일이 매우 중요해집니다.&lt;br /&gt;이럴 때 유용하게 사용할 수 있는 도구가 바로 &lt;b&gt;Pydantic&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ Pydantic이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pydantic은 &lt;b&gt;타입 힌트를 기반으로 데이터 유효성 검사를 자동으로 처리&lt;/b&gt;해주는 파이썬 라이브러리입니다.&lt;br /&gt;마치 &lt;code&gt;dataclass&lt;/code&gt;처럼 클래스를 정의하면, 자동으로 필드의 타입을 체크하고 잘못된 값이 들어올 경우 에러를 발생시켜 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FastAPI&lt;/b&gt;와 같은 웹 프레임워크에서 요청/응답 데이터를 검증할 때도 많이 사용됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 설치 방법&lt;/h2&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install pydantic&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 버전을 설치하려면 다음 명령어를 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;pip install --upgrade pydantic&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 기본 사용법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 데이터 모델 정의&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
    email: str
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 &lt;code&gt;BaseModel&lt;/code&gt;을 상속받아 클래스 정의 시, 각 필드에 대한 자동 타입 검증이 적용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 유효한 데이터 입력&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;user = User(name=&quot;김개발&quot;, age=30, email=&quot;dev@example.com&quot;)
print(user)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 잘못된 데이터 검증&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;try:
    user = User(name=&quot;김개발&quot;, age=&quot;스물다섯&quot;, email=&quot;잘못된 이메일&quot;)
except Exception as e:
    print(e)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 결과:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;2 validation errors for User
age
  value is not a valid integer (type=type_error.integer)
email
  value is not a valid email address (type=value_error.email)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자가 아닌 나이, 이메일 형식 오류를 Pydantic이 자동으로 잡아주는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 주요 기능&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기본값 설정&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class User(BaseModel):
    name: str
    age: int = 25  # 기본값 지정
    email: str
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;age&lt;/code&gt;를 생략하면 기본값 25가 자동으로 설정됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 데이터 자동 변환&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;class Product(BaseModel):
    name: str
    price: float
    in_stock: bool

product = Product(name=&quot;Laptop&quot;, price=&quot;1999.99&quot;, in_stock=&quot;True&quot;)
print(product)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;name='Laptop' price=1999.99 in_stock=True&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;3. 필드 조건 설정 (유효성 제약)&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from pydantic import BaseModel, Field

class Person(BaseModel):
    name: str = Field(..., min_length=2, max_length=10)
    age: int = Field(..., ge=18, le=99)

person = Person(name=&quot;홍길동&quot;, age=25)
print(person)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;min_length&lt;/code&gt;, &lt;code&gt;max_length&lt;/code&gt;, &lt;code&gt;ge&lt;/code&gt;, &lt;code&gt;le&lt;/code&gt; 등 다양한 제약 조건을 쉽게 설정할 수 있습니다.&lt;/p&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;b&gt;Pydantic&lt;/b&gt;은 Python에서 타입 힌트를 활용하여 데이터 검증을 간단하게 구현할 수 있도록 도와주는 라이브러리입니다.&lt;/li&gt;
&lt;li&gt;자동 타입 캐스팅, 유효성 검사, 기본값 지정, 조건 필터링 등 다양한 기능을 갖추고 있어 JSON 기반 데이터 처리나 API 응답 검증에 매우 적합합니다.&lt;/li&gt;
&lt;li&gt;코드를 더 안전하고, 명확하고, 유지보수하기 쉬운 구조로 만들어줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 입력이 많은 애플리케이션을 개발할 때, 특히 외부에서 입력되는 JSON 또는 사용자 요청 값을 신뢰할 수 없는 경우 &lt;b&gt;Pydantic을 사용하여 안정성을 확보&lt;/b&gt;하는 것을 추천합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;em&gt;※ 본 포스트는 Python 3.12 환경을 기준으로 작성되었습니다.&lt;/em&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>api데이터</category>
      <category>FastAPI</category>
      <category>json검증</category>
      <category>Pydantic</category>
      <category>Python</category>
      <category>python유효성검사</category>
      <category>데이터검증</category>
      <category>타입힌트</category>
      <category>파이썬</category>
      <category>파이썬라이브러리</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/161</guid>
      <comments>https://qratedev.tistory.com/161#entry161comment</comments>
      <pubDate>Thu, 20 Mar 2025 08:38:45 +0900</pubDate>
    </item>
    <item>
      <title>파이썬으로 네이버 주식 데이터 스크래핑하는 방법 (BeautifulSoup 사용)</title>
      <link>https://qratedev.tistory.com/160</link>
      <description>&lt;h1&gt;파이썬으로 네이버 주식 데이터 스크래핑하기 (BeautifulSoup 사용)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버 금융은 다양한 주식 정보를 빠르게 확인할 수 있는 유용한 플랫폼입니다. &lt;b&gt;파이썬(Python)&lt;/b&gt;을 사용하면 실시간 주식 데이터를 자동으로 수집하고 분석할 수 있습니다. 이 글에서는 &lt;b&gt;BeautifulSoup&lt;/b&gt;을 활용하여 네이버 주식 데이터를 가져오는 방법을 소개합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 필요한 라이브러리 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 페이지를 요청하고 HTML을 파싱하기 위해 아래 라이브러리를 설치합니다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install requests beautifulsoup4&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 네이버 주식 데이터 URL 분석&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버 금융에서 주식 정보를 확인하려면 종목 코드를 포함한 URL이 필요합니다.&lt;br /&gt;예시: &lt;b&gt;삼성전자(005930)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://finance.naver.com/item/main.nhn?code=005930&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; https://finance.naver.com/item/main.nhn?code=005930 &lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;code=005930&lt;/code&gt; 부분이 종목 코드를 의미하며, 다른 종목은 해당 코드만 변경하면 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 현재 주가 가져오기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼성전자의 현재 주가를 가져오는 파이썬 예제입니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import requests
from bs4 import BeautifulSoup

url = &quot;https://finance.naver.com/item/main.nhn?code=005930&quot;
response = requests.get(url)
soup = BeautifulSoup(response.text, &quot;html.parser&quot;)

price = soup.find(&quot;p&quot;, class_=&quot;no_today&quot;).find(&quot;span&quot;, class_=&quot;blind&quot;).text
print(f&quot;삼성전자 현재 주가: {price}원&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 전일 종가와 시가 정보 가져오기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전일 종가와 시가도 함께 가져올 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;data = soup.find_all(&quot;td&quot;, class_=&quot;first&quot;)

previous_close = data[0].find(&quot;span&quot;, class_=&quot;blind&quot;).text
open_price = data[1].find(&quot;span&quot;, class_=&quot;blind&quot;).text

print(f&quot;전일 종가: {previous_close}원&quot;)
print(f&quot;시가: {open_price}원&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. CSV 파일로 저장하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가져온 데이터를 CSV 파일로 저장해두면 나중에 분석할 때 유용합니다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;import csv

with open(&quot;stock_data.csv&quot;, &quot;w&quot;, newline=&quot;&quot;) as file:
    writer = csv.writer(file)
    writer.writerow([&quot;종목명&quot;, &quot;현재가&quot;, &quot;전일 종가&quot;, &quot;시가&quot;])
    writer.writerow([&quot;삼성전자&quot;, price, previous_close, open_price])

print(&quot;데이터가 stock_data.csv에 저장되었습니다.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 전체 코드 정리&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import requests
from bs4 import BeautifulSoup
import csv

url = &quot;https://finance.naver.com/item/main.nhn?code=005930&quot;
response = requests.get(url)
soup = BeautifulSoup(response.text, &quot;html.parser&quot;)

price = soup.find(&quot;p&quot;, class_=&quot;no_today&quot;).find(&quot;span&quot;, class_=&quot;blind&quot;).text
print(f&quot;삼성전자 현재 주가: {price}원&quot;)

data = soup.find_all(&quot;td&quot;, class_=&quot;first&quot;)
previous_close = data[0].find(&quot;span&quot;, class_=&quot;blind&quot;).text
open_price = data[1].find(&quot;span&quot;, class_=&quot;blind&quot;).text

print(f&quot;전일 종가: {previous_close}원&quot;)
print(f&quot;시가: {open_price}원&quot;)

with open(&quot;stock_data.csv&quot;, &quot;w&quot;, newline=&quot;&quot;) as file:
    writer = csv.writer(file)
    writer.writerow([&quot;종목명&quot;, &quot;현재가&quot;, &quot;전일 종가&quot;, &quot;시가&quot;])
    writer.writerow([&quot;삼성전자&quot;, price, previous_close, open_price])

print(&quot;데이터가 stock_data.csv에 저장되었습니다.&quot;)
&lt;/code&gt;&lt;/pre&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;b&gt;robots.txt 확인:&lt;/b&gt; 네이버의 &lt;a href=&quot;https://finance.naver.com/robots.txt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;robots.txt&lt;/a&gt;를 참고하여 허용된 범위 내에서 스크래핑을 진행해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요청 제한:&lt;/b&gt; 너무 짧은 시간 간격으로 요청을 보내면 IP 차단 등의 문제가 발생할 수 있으므로 &lt;code&gt;time.sleep()&lt;/code&gt;을 사용해 간격을 조절하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬과 BeautifulSoup을 활용하여 네이버 금융에서 주식 정보를 자동으로 수집하는 방법을 소개했습니다.&lt;br /&gt;이 방법을 활용하면 실시간 주식 데이터 분석이나 개인 포트폴리오 관리에 유용하게 사용할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;※ 본 글은 개인 학습 및 프로젝트 용도로 작성되었습니다. 웹 스크래핑 시에는 사이트의 이용약관과 정책을 반드시 확인하세요.&lt;/i&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>Beautifulsoup</category>
      <category>Finance</category>
      <category>Python</category>
      <category>네이버금융</category>
      <category>웹스크래핑</category>
      <category>자동화</category>
      <category>주가분석</category>
      <category>주식데이터</category>
      <category>주식자동수집</category>
      <category>파이썬</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/160</guid>
      <comments>https://qratedev.tistory.com/160#entry160comment</comments>
      <pubDate>Wed, 19 Mar 2025 18:00:47 +0900</pubDate>
    </item>
    <item>
      <title>[Python] Pillow 라이브러리로 이미지 처리하는 5가지 방법</title>
      <link>https://qratedev.tistory.com/159</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;파이썬으로 이미지 처리하기 - Pillow 라이브러리 사용법&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 처리는 컴퓨터 비전 분야에서 매우 중요한 역할을 합니다. 파이썬에서는 &lt;b&gt;Pillow&lt;/b&gt;라는 강력한 이미지 처리 라이브러리를 통해 디지털 이미지를 쉽게 다룰 수 있습니다. 이 글에서는 &lt;b&gt;이미지를 열고, 크기를 조정하고, 흑백으로 변환&lt;/b&gt;하며, &lt;b&gt;필터를 적용&lt;/b&gt;하는 방법까지 예제를 통해 설명합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Pillow 설치하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Pillow 라이브러리를 설치해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install pillow&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 이미지 열기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 이미지를 열고 화면에 표시하는 코드입니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;from PIL import Image

# 이미지 열기
img = Image.open('1.png')

# 이미지 표시
img.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 이미지 크기 조정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;resize()&lt;/code&gt; 메서드를 사용하면 이미지 크기를 간단하게 변경할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;# 이미지 크기 조정
new_img = img.resize((800, 600))

# 크기 조정된 이미지 표시
new_img.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 흑백 이미지로 변환&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;convert('L')&lt;/code&gt; 메서드를 사용하면 이미지를 흑백으로 변환할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 흑백 이미지로 변환
bw_img = img.convert('L')

# 흑백 이미지 표시
bw_img.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 이미지에 필터 적용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pillow는 다양한 이미지 필터를 지원합니다. 그중 하나인 &lt;b&gt;Gaussian Blur&lt;/b&gt; 필터를 적용하는 예제입니다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;from PIL import ImageFilter

# Gaussian Blur 필터 적용
blurred_img = img.filter(ImageFilter.GaussianBlur(5))

# 흐려진 이미지 표시
blurred_img.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 이미지 저장하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처리된 이미지는 &lt;code&gt;save()&lt;/code&gt; 메서드를 이용해 저장할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 이미지 저장
blurred_img.save('blurred_example.png')
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 전체 코드 모음&lt;/h2&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;from PIL import Image
from PIL import ImageFilter

# 이미지 열기
img = Image.open(r'C:\1.png')
img.show()

# 크기 조정
new_img = img.resize((800, 600))
new_img.show()

# 흑백 변환
bw_img = img.convert('L')
bw_img.show()

# 필터 적용
blurred_img = img.filter(ImageFilter.GaussianBlur(5))
blurred_img.show()

# 저장
blurred_img.save('blurred_example.png')
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 작업 결과 예시&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDQOCZ/btsMO6sfk5v/YGR40JHrCSUHSrqm0aqVj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDQOCZ/btsMO6sfk5v/YGR40JHrCSUHSrqm0aqVj0/img.png&quot; data-alt=&quot;원본 이미지 예시&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDQOCZ/btsMO6sfk5v/YGR40JHrCSUHSrqm0aqVj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDQOCZ%2FbtsMO6sfk5v%2FYGR40JHrCSUHSrqm0aqVj0%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;773&quot; height=&quot;454&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;원본 이미지 예시&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blurred_example.png&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ybFIb/btsMPkqCQrA/kIFg0rNb7VLKb8xgDQOAm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ybFIb/btsMPkqCQrA/kIFg0rNb7VLKb8xgDQOAm1/img.png&quot; data-alt=&quot;GaussianBlur 필터가 적용된 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ybFIb/btsMPkqCQrA/kIFg0rNb7VLKb8xgDQOAm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FybFIb%2FbtsMPkqCQrA%2FkIFg0rNb7VLKb8xgDQOAm1%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;773&quot; height=&quot;454&quot; data-filename=&quot;blurred_example.png&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;GaussianBlur 필터가 적용된 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 파이썬의 Pillow 라이브러리를 사용해 간단한 이미지 처리 작업을 해보았습니다. 크기 조정, 흑백 변환, 필터 적용 등 다양한 기능을 직접 실습해 보며 이미지 처리에 대한 이해를 넓혀보시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  추천 키워드:&lt;/b&gt; Python 이미지 처리, Pillow 튜토리얼, 파이썬 필터 효과&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>pillow</category>
      <category>python image processing</category>
      <category>이미지 필터</category>
      <category>컴퓨터 비전</category>
      <category>파이썬 pillow</category>
      <category>파이썬 기초</category>
      <category>파이썬 이미지 변환</category>
      <category>파이썬 이미지 처리</category>
      <category>파이썬 이미지 크기 조정</category>
      <category>파이썬 흑백 이미지</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/159</guid>
      <comments>https://qratedev.tistory.com/159#entry159comment</comments>
      <pubDate>Wed, 19 Mar 2025 14:24:19 +0900</pubDate>
    </item>
    <item>
      <title>[다이어트일지] #60: 2월 4주차 체중 운동 식단 피드백</title>
      <link>https://qratedev.tistory.com/158</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;체중은 일어나서 공복상태로 재기로 했습니다&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;일자: 2025.02.24 (월) ~ 2025.03.02 (일)&lt;br /&gt;지난주 최종 몸무게: 82.71kg&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;몸무게 (지난주 대비 변화:&lt;span style=&quot;color: #ef5369;&quot;&gt; +1.25kg&lt;/span&gt;)&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;02.24 (월):&lt;span style=&quot;color: #ef5369;&quot;&gt; 83.11kg&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;02.25 (화):&lt;span style=&quot;color: #0593d3;&quot;&gt; 83.00kg&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;02.26 (수): &lt;span style=&quot;color: #ef5369;&quot;&gt;83.28kg&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;02.27 (목):&lt;span style=&quot;color: #ef5369;&quot;&gt; -&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;02.28 (금):&lt;span style=&quot;color: #0593d3;&quot;&gt; 82.35kg&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;03.01 (토):&lt;span style=&quot;color: #ef5369;&quot;&gt; 82.66kg&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;03.02 (일):&lt;span style=&quot;color: #ef5369;&quot;&gt; 83.96kg&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;운동 루틴&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #333333;&quot;&gt;월:&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;휴식&lt;/span&gt;&lt;/s&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;화:&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가슴, 삼두&lt;/span&gt;&lt;br /&gt;&lt;s&gt;&lt;span style=&quot;color: #333333;&quot;&gt;수:&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 휴식&lt;/span&gt;&lt;/s&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;목:&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;등, 이두&lt;/span&gt;&lt;br /&gt;&lt;s&gt;금&lt;/s&gt;&lt;/span&gt;&lt;s&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;:&amp;nbsp;휴식&lt;/span&gt;&lt;/s&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;&lt;br /&gt;토: &lt;span style=&quot;color: #333333;&quot;&gt;어깨, 하체&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;&lt;/span&gt; &lt;br /&gt;&lt;s&gt;일:&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;휴식&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;피드백&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 지난주보다 &lt;b&gt;1.25kg이 증가&lt;/b&gt;했다. 특히 **주말(일요일)**에 체중이 확 올라간 게 눈에 띄었다. 전체적으로는 주중에 큰 변동 없이 잘 유지되었지만, 마지막 날에 갑자기 올라서 아쉬운 한 주였다.&lt;br /&gt;&lt;br /&gt;운동 루틴은 기존처&lt;b&gt;럼 잘 지&lt;/b&gt;켰고, 가슴/삼두 &amp;ndash; 등/이두&lt;b&gt; &amp;ndash; 어깨/하체로 나눠진 분할도 나에&lt;/b&gt;게 잘 맞는 구성이라고 느꼈다. 다만 이번 주처럼 휴식일이 많아지면 가벼운 유산&lt;b&gt;소나 스트레칭이라도 틈틈&lt;/b&gt;이 해주는 게 체중 유지에 도움이 될 것 같다.&lt;br /&gt;&lt;br /&gt;또 한 가지 느낀 건 주말 식단. 평일엔 식단&lt;b&gt;을 잘 지&lt;/b&gt;키고 있지만, 주말에 흐트러지면 일요일 체중이 확 올라가는 일이 생기는 것 같다. 평일뿐 아니라 주말 패턴도 안정적으로 유지&lt;b&gt;하는 것이 앞으로 중요한 포&lt;/b&gt;인트가 될 것 같다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: Noto Serif KR;&quot;&gt;이전글 보기&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://qratedev.tistory.com/151&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;2025.03.04 - [일상생활/다이어트일지] - [다이어트일지] #59: 2월 3주차 체중 운동 식단 피드백&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>일상생활/다이어트일지</category>
      <category>감량일기</category>
      <category>다이어터</category>
      <category>다이어트일지</category>
      <category>다이어트자극</category>
      <category>다이어트피드백</category>
      <category>몸무게변화</category>
      <category>운동루틴</category>
      <category>체중기록</category>
      <category>피트니스기록</category>
      <category>헬스일지</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/158</guid>
      <comments>https://qratedev.tistory.com/158#entry158comment</comments>
      <pubDate>Tue, 18 Mar 2025 13:00:32 +0900</pubDate>
    </item>
    <item>
      <title>파이썬으로 PDF 파일 처리하기: PyPDF2, pdfplumber 사용법 정리</title>
      <link>https://qratedev.tistory.com/157</link>
      <description>&lt;h1&gt;  파이썬으로 PDF 파일 다루기   PyPDF2와 pdfplumber 활용법 총정리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬(Python)을 사용하면 &lt;b&gt;PDF 파일을 쉽게 읽고 분석&lt;/b&gt;할 수 있습니다.&lt;br /&gt;특히 &lt;code&gt;PyPDF2&lt;/code&gt;와 &lt;code&gt;pdfplumber&lt;/code&gt;는 텍스트 추출, 페이지 수 확인, 특정 페이지 접근 등에 유용한 라이브러리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 두 라이브러리를 활용한&lt;/p&gt;
&lt;p&gt;&lt;mark&gt;PDF 처리 예제&lt;/mark&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 코드와 함께 정리해드립니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  PyPDF2 설치 및 사용법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 설치 방법&lt;/h3&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install PyPDF2&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. PDF 파일 열기 및 정보 확인&lt;/h3&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;import PyPDF2

with open('sample.pdf', 'rb') as file:
    reader = PyPDF2.PdfReader(file)
    print(f'페이지 수: {len(reader.pages)}')
    print('첫 페이지 내용:')
    print(reader.pages[0].extract_text())
&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;✔️ &lt;b&gt;페이지 수 확인&lt;/b&gt;: &lt;code&gt;len(reader.pages)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;✔️ &lt;b&gt;텍스트 추출&lt;/b&gt;: &lt;code&gt;page.extract_text()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  pdfplumber로 PDF 텍스트 정밀 추출&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 설치 방법&lt;/h3&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;pip install pdfplumber&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 예제 코드&lt;/h3&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;import pdfplumber

with pdfplumber.open(&quot;sample.pdf&quot;) as pdf:
    first_page = pdf.pages[0]
    text = first_page.extract_text()
    print(text)
&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;  &lt;b&gt;pdfplumber&lt;/b&gt;는 PyPDF2보다 &lt;u&gt;텍스트 추출 정확도&lt;/u&gt;가 높습니다.&lt;/li&gt;
&lt;li&gt;  특히 &lt;b&gt;표 형태&lt;/b&gt;나 &lt;b&gt;레이아웃&lt;/b&gt;을 유지한 텍스트가 필요할 때 유리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⚖️ PyPDF2 vs pdfplumber&lt;/h2&gt;
&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;PyPDF2&lt;/th&gt;
&lt;th&gt;pdfplumber&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&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;표(table) 추출&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF 구조 분석&lt;/td&gt;
&lt;td&gt;기본&lt;/td&gt;
&lt;td&gt;정밀&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;b&gt;단순 텍스트 추출&lt;/b&gt;이면 &lt;code&gt;PyPDF2&lt;/code&gt;만으로 충분&lt;/li&gt;
&lt;li&gt;  &lt;b&gt;표나 구조화된 내용&lt;/b&gt;이 필요하다면 &lt;code&gt;pdfplumber&lt;/code&gt; 사용 추천&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;  &lt;b&gt;PyPDF2&lt;/b&gt;: 가볍고 기본적인 PDF 처리에 적합&lt;/li&gt;
&lt;li&gt;  &lt;b&gt;pdfplumber&lt;/b&gt;: 정밀한 텍스트 추출에 강점&lt;/li&gt;
&lt;li&gt;  필요에 따라 &lt;b&gt;두 라이브러리를 병행&lt;/b&gt;하여 사용하면 더 강력&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>프로그래밍/Python</category>
      <category>pdf 추출</category>
      <category>pdfplumber</category>
      <category>pypdf2</category>
      <category>Python</category>
      <category>파이썬</category>
      <category>파이썬 pdf</category>
      <category>파이썬 pdf 읽기</category>
      <category>파이썬 pdf 처리</category>
      <category>파이썬 예제</category>
      <category>프로그래밍</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/157</guid>
      <comments>https://qratedev.tistory.com/157#entry157comment</comments>
      <pubDate>Tue, 18 Mar 2025 12:23:47 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 리스트 vs 딕셔너리 차이점 정리: 언제 어떤 자료형을 써야 할까?</title>
      <link>https://qratedev.tistory.com/156</link>
      <description>&lt;h1&gt;  파이썬 리스트 vs 딕셔너리, 언제 사용해야 할까? (초보자를 위한 쉬운 설명)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬(Python)을 처음 배우면 가장 많이 마주치는 자료형이 &lt;b&gt;리스트(List)&lt;/b&gt;와 &lt;b&gt;딕셔너리(Dictionary)&lt;/b&gt;입니다.&lt;br /&gt;하지만 둘의 차이와 사용 시점을 헷갈려하는 분들이 많아요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 ✅ 리스트와 딕셔너리의 차이, ✅ 예제 코드, ✅ 언제 사용해야 하는지를 정리해드립니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  리스트(List)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리스트&lt;/b&gt;는&lt;/p&gt;
&lt;p&gt;&lt;mark&gt;값들을 순서대로 나열한 자료형&lt;/mark&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입니다. 인덱스를 통해 각 요소에 접근합니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;fruits = ['apple', 'banana', 'orange']
print(fruits[0])  # apple
&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;✔️ &lt;b&gt;인덱스 기반 접근&lt;/b&gt; &amp;ndash; 순서가 중요할 때 유용&lt;/li&gt;
&lt;li&gt;✔️ &lt;b&gt;중복 허용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;✔️ &lt;b&gt;다양한 메서드&lt;/b&gt; &amp;ndash; append(), remove(), sort() 등&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  딕셔너리(Dictionary)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;딕셔너리&lt;/b&gt;는&lt;/p&gt;
&lt;p&gt;&lt;mark&gt;키(Key)와 값(Value)을 쌍으로 저장&lt;/mark&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하는 자료형입니다.&lt;/p&gt;
&lt;pre class=&quot;nsis&quot;&gt;&lt;code&gt;user = {
  'name': 'Alice',
  'age': 30
}
print(user['name'])  # Alice
&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;✔️ &lt;b&gt;키 기반 접근&lt;/b&gt; &amp;ndash; 식별자가 있는 데이터에 적합&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⚖️ 언제 리스트 vs 딕셔너리?&lt;/h2&gt;
&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&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;/thead&gt;
&lt;tbody&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;딕셔너리&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;딕셔너리의 리스트&lt;/td&gt;
&lt;td&gt;복합 데이터 표현 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  예제 비교: 사용자 정보 저장&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✔️ 리스트 사용&lt;/h3&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;users = ['Alice', 'Bob', 'Charlie']
print(users[1])  # Bob
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✔️ 딕셔너리 사용&lt;/h3&gt;
&lt;pre class=&quot;nsis&quot;&gt;&lt;code&gt;user = {
  'name': 'Alice',
  'age': 30,
  'email': 'alice@example.com'
}
print(user['email'])  # alice@example.com
&lt;/code&gt;&lt;/pre&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;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;b&gt;딕셔너리 안에 리스트&lt;/b&gt; 조합&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 리스트와 딕셔너리의 차이를 확실히 아셨죠?  &lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>Python</category>
      <category>Python dictionary</category>
      <category>Python List</category>
      <category>리스트 vs 딕셔너리</category>
      <category>파이썬</category>
      <category>파이썬 기초</category>
      <category>파이썬 데이터 구조</category>
      <category>파이썬 딕셔너리</category>
      <category>파이썬 리스트</category>
      <category>파이썬 자료형</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/156</guid>
      <comments>https://qratedev.tistory.com/156#entry156comment</comments>
      <pubDate>Tue, 18 Mar 2025 11:04:02 +0900</pubDate>
    </item>
    <item>
      <title>IIS 403.14 Forbidden 에러 해결 방법 (기본 문서 설정, 디렉터리 브라우징)</title>
      <link>https://qratedev.tistory.com/155</link>
      <description>&lt;h1&gt;[IIS] HTTP Error 403.14 - Forbidden 해결 방법&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디렉터리 브라우징이 비활성화되어 발생하는 에러&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IIS로 웹사이트를 배포한 후, 브라우저에서 접속했을 때 &lt;code&gt;HTTP Error 403.14 - Forbidden&lt;/code&gt; 에러를 본 적 있으신가요?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;에러 메시지:&lt;/b&gt; The Web server is configured to not list the contents of this directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에러는 흔히 &lt;b&gt;기본 문서가 설정되지 않았거나, 디렉터리 브라우징이 꺼져 있을 때&lt;/b&gt; 발생합니다.&lt;br /&gt;이번 글에서는 이 에러의 원인과 해결 방법을 간단히 정리해보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  원인 1: 기본 문서(Default Document) 설정 없음&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IIS는 접속 시 기본적으로 &lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;default.aspx&lt;/code&gt; 등의 기본 문서를 찾아 보여줍니다. 하지만 해당 파일이 없거나, IIS에 등록이 안 되어 있다면 403.14 에러가 발생할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IIS 관리자 실행&lt;/li&gt;
&lt;li&gt;해당 사이트 &amp;rarr; 더블클릭 &lt;b&gt;[기본 문서]&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;목록에 원하는 파일명 (&lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;home.aspx&lt;/code&gt; 등)이 있는지 확인&lt;/li&gt;
&lt;li&gt;없으면 우측 &lt;b&gt;[추가]&lt;/b&gt; 클릭 &amp;rarr; 파일명 입력 후 확인&lt;/li&gt;
&lt;li&gt;사이트 루트 폴더에 해당 파일이 존재하는지도 확인!&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  원인 2: 디렉터리 브라우징 비활성화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 문서가 없고 디렉터리 브라우징도 꺼져 있다면, IIS는 폴더 내용을 보여줄 수 없어 403.14 에러를 발생시킵니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IIS 관리자 실행&lt;/li&gt;
&lt;li&gt;해당 사이트 &amp;rarr; 더블클릭 &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;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;단, 보안상 디렉터리 브라우징은 가급적 비활성화 상태 유지 권장&lt;/i&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  보너스 팁: 웹.config에서 기본 문서 설정&lt;/h2&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;system.webServer&amp;gt;
    &amp;lt;defaultDocument&amp;gt;
      &amp;lt;files&amp;gt;
        &amp;lt;add value=&quot;index.html&quot; /&amp;gt;
      &amp;lt;/files&amp;gt;
    &amp;lt;/defaultDocument&amp;gt;
  &amp;lt;/system.webServer&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IIS에서 설정하기 번거로울 경우, &lt;code&gt;web.config&lt;/code&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;table border=&quot;1&quot; cellpadding=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;원인&lt;/th&gt;
&lt;th&gt;해결 방법&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;기본 문서 없음&lt;/td&gt;
&lt;td&gt;기본 문서 설정 or 파일 추가&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;웹.config 누락&lt;/td&gt;
&lt;td&gt;직접 기본 문서 설정 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에러는 단순하지만 처음 IIS 세팅할 땐 당황할 수 있습니다.&lt;br /&gt;위 방법대로 하나씩 점검해보시면 금방 해결될 거예요!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관련 키워드:&lt;/b&gt; iis http error 403.14, iis forbidden error fix, how to fix 403.14 error in iis, iis default document setting, windows server iis configuration&lt;/p&gt;</description>
      <category>프로그래밍/etc</category>
      <category>403.14 에러</category>
      <category>http error 403.14</category>
      <category>iis</category>
      <category>iis 설정</category>
      <category>iis 에러</category>
      <category>windows server</category>
      <category>개발자 팁</category>
      <category>기본 문서 설정</category>
      <category>디렉터리 브라우징</category>
      <category>웹.config</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/155</guid>
      <comments>https://qratedev.tistory.com/155#entry155comment</comments>
      <pubDate>Mon, 17 Mar 2025 13:18:40 +0900</pubDate>
    </item>
    <item>
      <title>  Python 개발자라면 꼭 알아야 할 PyCharm 꿀기능 4가지</title>
      <link>https://qratedev.tistory.com/154</link>
      <description>&lt;h1&gt;  PyCharm 꿀팁: 개발 환경 최적화하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Python 개발&lt;/b&gt;을 할 때 가장 많이 사용하는 IDE 중 하나가 &lt;b&gt;PyCharm&lt;/b&gt;입니다. 이 글에서는 개발 생산성을 높이는 &lt;b&gt;단축키&lt;/b&gt;, &lt;b&gt;가상 환경 설정&lt;/b&gt;, &lt;b&gt;디버깅&lt;/b&gt;, &lt;b&gt;Git 연동&lt;/b&gt; 팁을 소개합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  PyCharm 단축키 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 PyCharm에서 자주 사용하는 단축키입니다. &lt;b&gt;Windows / Linux&lt;/b&gt;와 &lt;b&gt;macOS&lt;/b&gt; 기준으로 함께 정리했어요.&lt;/p&gt;
&lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;Windows / Linux&lt;/th&gt;
&lt;th&gt;macOS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;  모든 기능 검색&lt;/td&gt;
&lt;td&gt;Ctrl + Shift + A&lt;/td&gt;
&lt;td&gt;Cmd + Shift + A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;  한 줄 주석&lt;/td&gt;
&lt;td&gt;Ctrl + /&lt;/td&gt;
&lt;td&gt;Cmd + /&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;  여러 줄 주석&lt;/td&gt;
&lt;td&gt;Ctrl + Shift + /&lt;/td&gt;
&lt;td&gt;Cmd + Shift + /&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;▶️ 코드 실행&lt;/td&gt;
&lt;td&gt;Shift + F10&lt;/td&gt;
&lt;td&gt;Ctrl + R&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;  코드 포맷팅&lt;/td&gt;
&lt;td&gt;Ctrl + Alt + L&lt;/td&gt;
&lt;td&gt;Cmd + Option + L&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;  최근 파일 보기&lt;/td&gt;
&lt;td&gt;Ctrl + E&lt;/td&gt;
&lt;td&gt;Cmd + E&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;  심볼 검색&lt;/td&gt;
&lt;td&gt;Ctrl + Alt + Shift + N&lt;/td&gt;
&lt;td&gt;Cmd + Option + O&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TIP:&lt;/b&gt; &lt;code&gt;Ctrl + Shift + A&lt;/code&gt;는 PyCharm의 모든 기능을 검색할 수 있어 &lt;i&gt;가장 유용한 단축키&lt;/i&gt; 중 하나입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  가상 환경(Virtual Environment) 관리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Python 프로젝트&lt;/b&gt;는 가상 환경을 사용하는 것이 중요합니다. 프로젝트마다 &lt;b&gt;독립된 패키지 환경&lt;/b&gt;을 구성하면 충돌 없이 안정적인 개발이 가능합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✔️ 설정 방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;File &amp;gt; Settings &amp;gt; Project: [프로젝트명] &amp;gt; Python Interpreter&lt;/code&gt; 메뉴로 이동&lt;/li&gt;
&lt;li&gt;오른쪽 상단의 톱니바퀴 클릭 &amp;gt; &lt;b&gt;Add...&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Virtualenv Environment&lt;/b&gt; 선택 후 경로 및 Python 버전 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TIP:&lt;/b&gt; &lt;code&gt;requirements.txt&lt;/code&gt;를 만들어 가상 환경을 쉽게 공유하세요.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/4/4c/Virtualenv-pycharm.gif&quot; alt=&quot;PyCharm 가상환경 설정 예시&quot; width=&quot;100%&quot; /&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  PyCharm 디버깅 기능 활용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;print()&lt;/b&gt; 대신 &lt;b&gt;중단점(Breakpoint)&lt;/b&gt;을 사용하면 코드 흐름을 더 쉽게 파악할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  기본 디버깅 방법&lt;/h3&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;code&gt;Shift + F9&lt;/code&gt; (또는 오른쪽 상단 벌레 모양 아이콘)&lt;/li&gt;
&lt;li&gt;Watch, Evaluate Expression 창에서 변수 추적&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TIP:&lt;/b&gt; 중단점에서 &lt;i&gt;Log to console&lt;/i&gt; 옵션을 활성화하면, 변수 값을 자동 출력할 수 있어요.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.jetbrains.com/pycharm/guide/tips/debugging-basics/debugger-1.png&quot; alt=&quot;PyCharm 디버깅 예시 화면&quot; width=&quot;100%&quot; /&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Git 연동으로 협업도 문제없어요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyCharm은 Git과 완벽하게 통합되어 있어 &lt;b&gt;버전 관리&lt;/b&gt;를 GUI 환경에서 손쉽게 할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  Git 사용 방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;VCS &amp;gt; Enable Version Control Integration&lt;/code&gt; 클릭&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Git&lt;/b&gt; 선택 후 프로젝트와 연동&lt;/li&gt;
&lt;li&gt;하단의 Git 탭에서 커밋, 푸시, 변경 내역 확인 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TIP:&lt;/b&gt; 커밋 전에 &lt;code&gt;Code &amp;gt; Inspect Code&lt;/code&gt; 기능으로 코드 품질을 점검하세요.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://resources.jetbrains.com/help/img/idea/2023.1/git-log-tool-window.png&quot; alt=&quot;PyCharm Git 연동 예시 화면&quot; width=&quot;100%&quot; /&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 마무리: PyCharm으로 개발을 더 스마트하게!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 설정이 번거롭게 느껴질 수 있지만, &lt;b&gt;단축키&lt;/b&gt;, &lt;b&gt;가상 환경&lt;/b&gt;, &lt;b&gt;디버깅&lt;/b&gt;, &lt;b&gt;Git 연동&lt;/b&gt;을 익혀두면 &lt;b&gt;개발 속도와 품질&lt;/b&gt;이 모두 향상됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PyCharm은 단순한 에디터가 아닌, &lt;b&gt;당신의 최고의 개발 파트너&lt;/b&gt;입니다  ✨&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;이 포스팅이 도움이 되셨다면 댓글이나 공감 부탁드려요! 더 많은 개발 꿀팁을 준비 중입니다  &lt;/i&gt;&lt;/p&gt;</description>
      <category>프로그래밍/Python</category>
      <category>Pycharm</category>
      <category>Pycharm 단축키</category>
      <category>Python</category>
      <category>Python IDE</category>
      <category>python 가상환경</category>
      <category>가상환경 설정</category>
      <category>개발툴추천</category>
      <category>파이썬 디버깅</category>
      <category>파이썬개발</category>
      <category>파이참</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/154</guid>
      <comments>https://qratedev.tistory.com/154#entry154comment</comments>
      <pubDate>Fri, 14 Mar 2025 16:58:02 +0900</pubDate>
    </item>
    <item>
      <title>[Tool] VS Code 필수 단축키 &amp;amp; 확장 프로그램 완벽 정리</title>
      <link>https://qratedev.tistory.com/153</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! 오늘은 VS Code를 더 효율적으로 사용할 수 있는 꿀팁들을 정리해보았습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;필수 단축키 모음&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &amp;nbsp;기본&amp;nbsp;조작 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;P&amp;nbsp;:&amp;nbsp;빠른&amp;nbsp;파일&amp;nbsp;열기 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;P&amp;nbsp;:&amp;nbsp;모든&amp;nbsp;명령&amp;nbsp;표시 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;`&amp;nbsp;:&amp;nbsp;터미널&amp;nbsp;열기/닫기 &lt;br /&gt;-&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;&amp;uarr;/&amp;darr;&amp;nbsp;:&amp;nbsp;현재&amp;nbsp;줄&amp;nbsp;이동 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;L&amp;nbsp;:&amp;nbsp;현재&amp;nbsp;줄&amp;nbsp;선택 &lt;br /&gt;&lt;br /&gt; &amp;nbsp;코드&amp;nbsp;편집 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;D&amp;nbsp;:&amp;nbsp;같은&amp;nbsp;단어&amp;nbsp;선택&amp;nbsp;(여러&amp;nbsp;번&amp;nbsp;누르면&amp;nbsp;다중&amp;nbsp;선택) &lt;br /&gt;-&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;Click&amp;nbsp;:&amp;nbsp;다중&amp;nbsp;커서 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;/&amp;nbsp;:&amp;nbsp;주석&amp;nbsp;처리/해제 &lt;br /&gt;-&amp;nbsp;Shift&amp;nbsp;+&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;F&amp;nbsp;:&amp;nbsp;코드&amp;nbsp;자동&amp;nbsp;정렬 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;Space&amp;nbsp;:&amp;nbsp;자동&amp;nbsp;완성&amp;nbsp;제안 &lt;br /&gt;&lt;br /&gt; &amp;nbsp;화면&amp;nbsp;관리 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;B&amp;nbsp;:&amp;nbsp;사이드바&amp;nbsp;열기/닫기 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;\&amp;nbsp;:&amp;nbsp;화면&amp;nbsp;분할 &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;Tab&amp;nbsp;:&amp;nbsp;열린&amp;nbsp;파일&amp;nbsp;간&amp;nbsp;이동&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;추천 확장 프로그램&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;코딩&amp;nbsp;필수품 &lt;br /&gt;-&amp;nbsp;GitHub&amp;nbsp;Copilot&amp;nbsp;:&amp;nbsp;AI&amp;nbsp;코드&amp;nbsp;자동&amp;nbsp;완성 &lt;br /&gt;-&amp;nbsp;GitLens&amp;nbsp;:&amp;nbsp;Git&amp;nbsp;이력&amp;nbsp;관리&amp;nbsp;강화 &lt;br /&gt;-&amp;nbsp;Error&amp;nbsp;Lens&amp;nbsp;:&amp;nbsp;인라인&amp;nbsp;에러&amp;nbsp;표시 &lt;br /&gt;-&amp;nbsp;Auto&amp;nbsp;Rename&amp;nbsp;Tag&amp;nbsp;:&amp;nbsp;HTML/XML&amp;nbsp;태그&amp;nbsp;자동&amp;nbsp;수정 &lt;br /&gt;&lt;br /&gt;2.&amp;nbsp;코드&amp;nbsp;품질 &lt;br /&gt;-&amp;nbsp;ESLint&amp;nbsp;:&amp;nbsp;자바스크립트&amp;nbsp;코드&amp;nbsp;검사 &lt;br /&gt;-&amp;nbsp;Prettier&amp;nbsp;:&amp;nbsp;코드&amp;nbsp;자동&amp;nbsp;정렬 &lt;br /&gt;-&amp;nbsp;Code&amp;nbsp;Spell&amp;nbsp;Checker&amp;nbsp;:&amp;nbsp;영문&amp;nbsp;스펠링&amp;nbsp;체크 &lt;br /&gt;-&amp;nbsp;SonarLint&amp;nbsp;:&amp;nbsp;코드&amp;nbsp;품질&amp;nbsp;검사 &lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;테마&amp;nbsp;&amp;amp;&amp;nbsp;UI &lt;br /&gt;-&amp;nbsp;Material&amp;nbsp;Icon&amp;nbsp;Theme&amp;nbsp;:&amp;nbsp;파일&amp;nbsp;아이콘&amp;nbsp;테마 &lt;br /&gt;-&amp;nbsp;One&amp;nbsp;Dark&amp;nbsp;Pro&amp;nbsp;:&amp;nbsp;인기&amp;nbsp;다크&amp;nbsp;테마 &lt;br /&gt;-&amp;nbsp;Indent&amp;nbsp;Rainbow&amp;nbsp;:&amp;nbsp;들여쓰기&amp;nbsp;색상&amp;nbsp;표시 &lt;br /&gt;&lt;br /&gt;4.&amp;nbsp;생산성&amp;nbsp;도구 &lt;br /&gt;-&amp;nbsp;Live&amp;nbsp;Server&amp;nbsp;:&amp;nbsp;실시간&amp;nbsp;미리보기&amp;nbsp;서버 &lt;br /&gt;-&amp;nbsp;Thunder&amp;nbsp;Client&amp;nbsp;:&amp;nbsp;API&amp;nbsp;테스트&amp;nbsp;도구 &lt;br /&gt;-&amp;nbsp;Code&amp;nbsp;Runner&amp;nbsp;:&amp;nbsp;코드&amp;nbsp;즉시&amp;nbsp;실행&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;추천 설정&lt;/blockquote&gt;
&lt;pre id=&quot;code_1741935350549&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;editor.fontSize&quot;: 14,
    &quot;editor.fontFamily&quot;: &quot;D2Coding, Consolas, monospace&quot;,
    &quot;editor.wordWrap&quot;: &quot;on&quot;,
    &quot;editor.minimap.enabled&quot;: false,
    &quot;editor.formatOnSave&quot;: true,
    &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;,
    &quot;files.autoSave&quot;: &quot;afterDelay&quot;,
    &quot;workbench.colorTheme&quot;: &quot;One Dark Pro&quot;,
    &quot;terminal.integrated.defaultProfile.windows&quot;: &quot;Git Bash&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;작업 효율을 높이는 팁&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&amp;nbsp;스니펫&amp;nbsp;활용하기 &lt;br /&gt;-&amp;nbsp;자주&amp;nbsp;사용하는&amp;nbsp;코드&amp;nbsp;조각을&amp;nbsp;저장 &lt;br /&gt;-&amp;nbsp;커스텀&amp;nbsp;스니펫&amp;nbsp;만들기 &lt;br /&gt;&lt;br /&gt;2.&amp;nbsp;작업&amp;nbsp;영역&amp;nbsp;설정 &lt;br /&gt;-&amp;nbsp;프로젝트별&amp;nbsp;설정&amp;nbsp;관리 &lt;br /&gt;-&amp;nbsp;.vscode&amp;nbsp;폴더&amp;nbsp;활용 &lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;다중&amp;nbsp;커서&amp;nbsp;활용 &lt;br /&gt;-&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;Click &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;Alt&amp;nbsp;+&amp;nbsp;&amp;uarr;/&amp;darr; &lt;br /&gt;-&amp;nbsp;Ctrl&amp;nbsp;+&amp;nbsp;D &lt;br /&gt;&lt;br /&gt;4.&amp;nbsp;터미널&amp;nbsp;통합&amp;nbsp;활용 &lt;br /&gt;-&amp;nbsp;Git&amp;nbsp;명령어&amp;nbsp;실행 &lt;br /&gt;-&amp;nbsp;NPM&amp;nbsp;패키지&amp;nbsp;관리 &lt;br /&gt;-&amp;nbsp;빌드&amp;nbsp;및&amp;nbsp;실행&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;마무리&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의&amp;nbsp;설정들을&amp;nbsp;적용하면&amp;nbsp;VS&amp;nbsp;Code를&amp;nbsp;훨씬&amp;nbsp;더&amp;nbsp;효율적으로&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;특히&amp;nbsp;단축키는&amp;nbsp;처음에는&amp;nbsp;어색할&amp;nbsp;수&amp;nbsp;있지만,&amp;nbsp;자주&amp;nbsp;사용하다&amp;nbsp;보면&amp;nbsp;작업&amp;nbsp;속도가&amp;nbsp;크게&amp;nbsp;향상됩니다. &lt;br /&gt;&lt;br /&gt;이&amp;nbsp;글이&amp;nbsp;도움이&amp;nbsp;되셨다면&amp;nbsp;좋아요와&amp;nbsp;공유&amp;nbsp;부탁드립니다!&amp;nbsp; &lt;/p&gt;</description>
      <category>프로그래밍/etc</category>
      <author>큐레이트</author>
      <guid isPermaLink="true">https://qratedev.tistory.com/153</guid>
      <comments>https://qratedev.tistory.com/153#entry153comment</comments>
      <pubDate>Fri, 14 Mar 2025 15:57:40 +0900</pubDate>
    </item>
  </channel>
</rss>