Skip to content

Commit 42510de

Browse files
docs(blog): 11차 배치 팁 포스트 5개 추가 (3개 언어)
1 parent 3b32b4b commit 42510de

15 files changed

Lines changed: 986 additions & 0 deletions
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
layout: post
3+
title: "Create Immutable Data Objects with Python dataclass(frozen=True)"
4+
date: 2026-01-29 09:00:00 +0900
5+
categories: [Development, Tips]
6+
tags: [Python, dataclass, Type-Safety, Backend]
7+
author: "Kevin Park"
8+
lang: en
9+
excerpt: "Use Python's frozen dataclass to create immutable objects with built-in validation and hashability."
10+
---
11+
12+
## Problem
13+
14+
You create objects to hold configuration or API response data, but accidental mutations somewhere in the code lead to painful debugging sessions. Dictionaries lack type hints, and making regular classes immutable requires boilerplate.
15+
16+
## Solution
17+
18+
`dataclass(frozen=True)` solves this in one line.
19+
20+
```python
21+
from dataclasses import dataclass
22+
23+
@dataclass(frozen=True)
24+
class DatabaseConfig:
25+
host: str
26+
port: int
27+
name: str
28+
max_connections: int = 10
29+
30+
config = DatabaseConfig(host="localhost", port=5432, name="myapp")
31+
32+
config.port = 3306 # FrozenInstanceError!
33+
```
34+
35+
Add creation-time validation with `__post_init__`:
36+
37+
```python
38+
@dataclass(frozen=True)
39+
class PriceRange:
40+
min_price: float
41+
max_price: float
42+
43+
def __post_init__(self):
44+
if self.min_price < 0:
45+
raise ValueError("min_price must be >= 0")
46+
if self.min_price > self.max_price:
47+
raise ValueError("min_price cannot exceed max_price")
48+
```
49+
50+
Frozen dataclasses are hashable, so they work as dictionary keys or set members:
51+
52+
```python
53+
@dataclass(frozen=True)
54+
class Coordinate:
55+
x: float
56+
y: float
57+
58+
visited = set()
59+
visited.add(Coordinate(1.0, 2.0)) # Works as a set member
60+
```
61+
62+
## Key Points
63+
64+
- `@dataclass(frozen=True)` creates immutable objects with minimal boilerplate
65+
- Any mutation attempt raises `FrozenInstanceError`
66+
- Use `__post_init__` for creation-time validation
67+
- Frozen dataclasses are hashable — usable as dict keys and set members
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
layout: post
3+
title: "Python dataclass(frozen=True)で不変データオブジェクトを作成する"
4+
date: 2026-01-29 09:00:00 +0900
5+
categories: [Development, Tips]
6+
tags: [Python, dataclass, 型安全, バックエンド]
7+
author: "Kevin Park"
8+
lang: ja
9+
excerpt: "Pythonのfrozen dataclassを使って、不変オブジェクトを簡単に作成する方法を解説します。"
10+
---
11+
12+
## 問題
13+
14+
設定値やAPIレスポンスデータを保持するオブジェクトを作成したものの、コードのどこかで誤って値が変更されると、デバッグが非常に困難になります。辞書型ではタイプヒントが効かず、通常のクラスで不変にするにはボイラープレートが必要です。
15+
16+
## 解決方法
17+
18+
`dataclass(frozen=True)`を使えば、1行で解決できます。
19+
20+
```python
21+
from dataclasses import dataclass
22+
23+
@dataclass(frozen=True)
24+
class DatabaseConfig:
25+
host: str
26+
port: int
27+
name: str
28+
max_connections: int = 10
29+
30+
config = DatabaseConfig(host="localhost", port=5432, name="myapp")
31+
32+
config.port = 3306 # FrozenInstanceError!
33+
```
34+
35+
`__post_init__`で生成時のバリデーションも可能です。
36+
37+
```python
38+
@dataclass(frozen=True)
39+
class PriceRange:
40+
min_price: float
41+
max_price: float
42+
43+
def __post_init__(self):
44+
if self.min_price < 0:
45+
raise ValueError("min_priceは0以上である必要があります")
46+
if self.min_price > self.max_price:
47+
raise ValueError("min_priceがmax_priceを超えることはできません")
48+
```
49+
50+
frozen dataclassはハッシュ可能なので、辞書のキーやsetの要素としても使えます。
51+
52+
```python
53+
@dataclass(frozen=True)
54+
class Coordinate:
55+
x: float
56+
y: float
57+
58+
visited = set()
59+
visited.add(Coordinate(1.0, 2.0)) # setに追加可能
60+
```
61+
62+
## ポイント
63+
64+
- `@dataclass(frozen=True)`で最小限のコードで不変オブジェクトを作成できます
65+
- 属性の変更を試みると`FrozenInstanceError`が発生します
66+
- `__post_init__`で生成時のバリデーションが可能です
67+
- frozen dataclassはハッシュ可能なので、dictのキーやsetの要素として使用できます
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
layout: post
3+
title: "Python dataclass(frozen=True)로 불변 데이터 객체 만들기"
4+
date: 2026-01-29 09:00:00 +0900
5+
categories: [Development, Tips]
6+
tags: [Python, dataclass, 타입안전, 백엔드]
7+
author: "Kevin Park"
8+
lang: ko
9+
excerpt: "Python dataclass에 frozen=True를 쓰면 불변 객체를 간단하게 만들 수 있다. 설정값이나 상수 객체에 딱이다."
10+
---
11+
12+
## 문제
13+
14+
설정값이나 API 응답 데이터를 담는 객체를 만들었는데, 코드 어딘가에서 실수로 값이 변경되면 디버깅이 지옥이 된다. 딕셔너리로 넘기면 타입 힌트도 안 되고, 일반 클래스로 만들면 `__setattr__` 오버라이드하고 난리를 쳐야 한다.
15+
16+
## 해결
17+
18+
`dataclass(frozen=True)`를 쓰면 한 줄로 해결된다.
19+
20+
```python
21+
from dataclasses import dataclass
22+
23+
@dataclass(frozen=True)
24+
class DatabaseConfig:
25+
host: str
26+
port: int
27+
name: str
28+
max_connections: int = 10
29+
30+
config = DatabaseConfig(
31+
host="localhost",
32+
port=5432,
33+
name="myapp"
34+
)
35+
36+
# 값 변경 시도하면 에러 발생
37+
config.port = 3306 # FrozenInstanceError!
38+
```
39+
40+
`__post_init__`으로 생성 시점 검증도 가능하다.
41+
42+
```python
43+
@dataclass(frozen=True)
44+
class PriceRange:
45+
min_price: float
46+
max_price: float
47+
48+
def __post_init__(self):
49+
if self.min_price < 0:
50+
# frozen이라 object.__setattr__ 사용
51+
raise ValueError("min_price는 0 이상이어야 한다")
52+
if self.min_price > self.max_price:
53+
raise ValueError("min_price가 max_price보다 클 수 없다")
54+
```
55+
56+
frozen dataclass는 해시 가능해서 딕셔너리 키나 set 원소로도 쓸 수 있다.
57+
58+
```python
59+
@dataclass(frozen=True)
60+
class Coordinate:
61+
x: float
62+
y: float
63+
64+
visited = set()
65+
visited.add(Coordinate(1.0, 2.0)) # set에 넣을 수 있다
66+
```
67+
68+
## 핵심 포인트
69+
70+
- `@dataclass(frozen=True)`로 불변 객체를 간단하게 생성
71+
- 속성 변경 시도 시 `FrozenInstanceError` 발생
72+
- `__post_init__`으로 생성 시점 검증 가능
73+
- frozen dataclass는 hashable이라 dict 키나 set 원소로 사용 가능
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
layout: post
3+
title: "Reduce Selector Repetition with CSS :is() and :where()"
4+
date: 2026-01-30 09:00:00 +0900
5+
categories: [Development, Tips]
6+
tags: [CSS, Selectors, Frontend, Web-Development]
7+
author: "Kevin Park"
8+
lang: en
9+
excerpt: "How to use CSS :is() and :where() to eliminate repetitive selectors, and the key specificity difference between them."
10+
---
11+
12+
## Problem
13+
14+
Applying similar styles to multiple elements requires listing out selectors repeatedly:
15+
16+
```css
17+
.article h1,
18+
.article h2,
19+
.article h3,
20+
.article h4 {
21+
color: #333;
22+
line-height: 1.4;
23+
}
24+
```
25+
26+
This gets tedious fast, especially with nested contexts.
27+
28+
## Solution
29+
30+
`:is()` lets you group selector lists:
31+
32+
```css
33+
.article :is(h1, h2, h3, h4) {
34+
color: #333;
35+
line-height: 1.4;
36+
}
37+
38+
/* Group both sides */
39+
:is(.article, .sidebar) :is(h1, h2, h3, h4) {
40+
line-height: 1.4;
41+
}
42+
```
43+
44+
`:where()` has the same syntax but **always has zero specificity**:
45+
46+
```css
47+
/* :is() - takes the highest specificity argument */
48+
:is(.class, #id) p { } /* specificity: (1,0,1) */
49+
50+
/* :where() - always zero specificity */
51+
:where(.class, #id) p { } /* specificity: (0,0,1) */
52+
```
53+
54+
This makes `:where()` ideal for default styles that should be easy to override:
55+
56+
```css
57+
/* Base styles - easily overridable */
58+
:where(.btn) {
59+
padding: 8px 16px;
60+
border-radius: 4px;
61+
}
62+
63+
/* Simple class override works */
64+
.my-btn {
65+
padding: 12px 24px;
66+
}
67+
```
68+
69+
## Key Points
70+
71+
- Both `:is()` and `:where()` group selector lists to reduce repetition
72+
- `:is()` adopts the highest specificity among its arguments
73+
- `:where()` always contributes zero specificity, making overrides easy
74+
- Use `:where()` for resets/libraries, `:is()` for component styles
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
layout: post
3+
title: "CSS :is()と:where()セレクタで重複セレクタを減らす方法"
4+
date: 2026-01-30 09:00:00 +0900
5+
categories: [Development, Tips]
6+
tags: [CSS, セレクタ, フロントエンド, Web開発]
7+
author: "Kevin Park"
8+
lang: ja
9+
excerpt: "CSS :is()と:where()で繰り返しのセレクタをスッキリ減らす方法と、両者のspecificity の違いを解説します。"
10+
---
11+
12+
## 問題
13+
14+
CSSで似たようなスタイルを複数の要素に適用するには、セレクタを長々と列挙する必要があります。
15+
16+
```css
17+
.article h1,
18+
.article h2,
19+
.article h3,
20+
.article h4 {
21+
color: #333;
22+
line-height: 1.4;
23+
}
24+
```
25+
26+
見ているだけで疲れてしまいます。
27+
28+
## 解決方法
29+
30+
`:is()`を使えば、セレクタリストをグループ化できます。
31+
32+
```css
33+
.article :is(h1, h2, h3, h4) {
34+
color: #333;
35+
line-height: 1.4;
36+
}
37+
38+
/* 両方をグループ化することも可能 */
39+
:is(.article, .sidebar) :is(h1, h2, h3, h4) {
40+
line-height: 1.4;
41+
}
42+
```
43+
44+
`:where()`も構文は同じですが、**specificityが常に0**という違いがあります。
45+
46+
```css
47+
/* :is() - 最も高いspecificityの引数に従う */
48+
:is(.class, #id) p { } /* specificity: (1,0,1) */
49+
50+
/* :where() - 常にspecificity 0 */
51+
:where(.class, #id) p { } /* specificity: (0,0,1) */
52+
```
53+
54+
そのため、`:where()`は簡単にオーバーライドできるデフォルトスタイルに最適です。
55+
56+
```css
57+
/* ベーススタイル - 後から簡単に上書き可能 */
58+
:where(.btn) {
59+
padding: 8px 16px;
60+
border-radius: 4px;
61+
}
62+
63+
/* このシンプルなクラスで上書きできます */
64+
.my-btn {
65+
padding: 12px 24px;
66+
}
67+
```
68+
69+
## ポイント
70+
71+
- `:is()``:where()`はセレクタリストをグループ化して重複を減らします
72+
- `:is()`は引数の中で最も高いspecificityを採用します
73+
- `:where()`はspecificityが常に0なので、オーバーライドが簡単です
74+
- リセットCSS/ライブラリには`:where()`、コンポーネントスタイルには`:is()`が適しています

0 commit comments

Comments
 (0)