Skip to content

๊ฐœ์ธ์ ์œผ๋กœ ํŒŒ์ด์ฌ์„ ์ข‹์•„ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, AI ์‹œ๋Œ€์— ์žˆ์–ด ํŒŒ์ด์ฌ์„ ์–ธ์ œ๊นŒ์ง€๋‚˜ ๊ธฐํ”ผํ•  ์ˆ˜ ์—†๋‹ค. ๋น„๋ก ํŒŒ์ด์ฌ์œผ๋กœ ๊ฐœ๋ฐœํ•˜์ง€ ์•Š๋”๋ผ๋„ ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ ๋ณด๊ณ  ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์—ญ๋Ÿ‰์„ ํ‚ค์›Œ๋ณด์ž. ํŒŒ์ด์ฌ์€ ๊ฐœ๋ฐœ์ž ๋ณด๋‹ค๋Š” DevOps ์—”์ง€๋‹ˆ์–ด ๋˜๋Š” QA ์—”์ง€๋‹ˆ์–ด ๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ ๋ถ„์„ ์—”์ง€๋‹ˆ์–ด๊ฐ€ ๋งŽ์ด ํ™œ์šฉํ•œ๋‹ค.

ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ โ€‹

ํŒŒ์ด์ฌ์€ ์ปดํŒŒ์ผ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ๋ฅผ ํ•œ์ค„์”ฉ ๊ทธ๋Œ€๋กœ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์— ์˜ํ•ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ๊ธฐ๋ณธ์ ์ธ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” CPython ์ด๋ฉฐ, pip ๋˜๋Š” uv ๋Š” ํŒŒ์ด์ฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ €์ด๋‹ค. ํŒŒ์ด์ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๊ฐ€ ์ •ํ™•ํžˆ ์–ด๋–ค ๊ณผ์ •์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š”์ง€๋Š” ์ž์„ธํžˆ ์•Œ ํ•„์š”๋Š” ์—†์–ด๋ณด์ธ๋‹ค.

๋ชจ๋“ˆ ๋””๋ ‰ํ† ๋ฆฌ โ€‹

ํŒŒ์ด์ฌ์€ ๋ณ€์ˆ˜ ๋˜๋Š” ํ•จ์ˆ˜ ๊ทธ๋ฆฌ๊ณ  ํด๋ž˜์Šค ๋“ฑ์„ ํ•˜๋‚˜์˜ .py ํŒŒ์ผ์— ์ •์˜ํ•˜์—ฌ ๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋“ˆํ™”ํ•œ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž‘์„ฑ์„ ์œ„ํ•ด FastAPI ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๋ฉด ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์™€์„œ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ๋ชจ๋“ˆ ํŒŒ์ผ์ด ์กด์žฌํ•˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ์— __init__.py ํŒŒ์ผ์ด ์กด์žฌํ•˜๋ฉด ํ•ด๋‹น ํด๋”๋Š” ํŒจํ‚ค์ง€๋กœ ์ทจ๊ธ‰๋œ๋‹ค. Best Practices ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ๋ฅผ ์ฐพ์•„๋ณด๋ฉด ํŒŒ์ผ ๊ตฌ์กฐ ์ƒ์— ์ด ํŒŒ์ผ์ด ์—†์„ ์ˆ˜ ์žˆ๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ ์ƒ๋žต์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

python
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def index():
    return {"Hello": "World"}

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ โ€‹

ํŒŒ์ด์ฌ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ํŒจํ„ด์ด๋‹ค. FastAPI์—์„œ ๋ผ์šฐํ„ฐ๋ฅผ ๋“ฑ๋กํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ Cache๋ฅผ ํ†ตํ•ด ํŒŒ์ด์ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š”๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํƒ€์ด๋ฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํ•จ์ˆ˜์˜ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜์—ฌ ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋‚ด์žฌ๋œ ๊ตฌ๊ฐ„์„ ์ฐพ๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค.

python
import functools
import time

def timing_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"ํ•จ์ˆ˜ '{func.__name__}' ์‹คํ–‰ ์‹œ๊ฐ„: {end_time - start_time:.4f} ์ดˆ")
        return result
    return wrapper

@timing_decorator
def example_function(n):
    total = 0
    for i in range(n):
        total += i
    return total

if __name__ == '__main__':
    example_function(10000000)

SQLAlchemy vs SQLModel โ€‹

SQLAlchemy ORM์€ ํŒŒ์ด์ฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ORM ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ SQLite ์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค . FastAPI ์—์„œ ์ œ๊ณตํ•˜๋Š” SQLModel ์€ SQLAlchemy ๊ธฐ๋ฐ˜์—์„œ Pydantic ์ด ๊ฒฐํ•ฉ๋œ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•œ๋‹ค. SQLModel ์„ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” SQLAlchemy ๋ฅผ ๋จผ์ € ํ•™์Šตํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค. ๋‹ค์Œ์€ AWS IoT Core ์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ IoT ํด๋ผ์ด์–ธํŠธ ์ธ์ฆ์„œ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ํ…Œ์ด๋ธ”์„ ์ •์˜ํ•ด๋ณธ ๊ฒƒ์ด๋‹ค.

python
from datetime import datetime
from sqlmodel import Field, Session, SQLModel, create_engine, Column, LargeBinary
from sqlalchemy.dialects.sqlite import insert


class IoT(SQLModel, table=True):
    __tablename__ = "iot"
    __table_args__ = {"sqlite_autoincrement": True, "comment": "AWS IoT Thing"}

    id: int = Field(default=None, primary_key=True)
    client_id: str = Field(nullable=False, unique=True)
    private_key: bytes = Field(sa_column=Column(LargeBinary, nullable=False))
    cert_pem: bytes = Field(sa_column=Column(LargeBinary, nullable=False))
    ca_cert_pem: bytes | None = Field(sa_column=Column(LargeBinary, nullable=True))
    created_at: datetime = Field(default_factory=lambda: datetime.now(), nullable=False)


engine = create_engine(
    "sqlite:///./db/app.db", echo=True, pool_size=5, pool_recycle=3600
)
SQLModel.metadata.create_all(engine)
session = Session(engine)

stmt = (
    insert(IoT)
    .values(client_id="asdf", private_key=b"", cert_pem=b"")
    .on_conflict_do_nothing()
)
session.exec(stmt)
session.commit()

Pandas vs Polars โ€‹

ํŒŒ์ด์ฌ ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ฐ ๋ถ„์„์„ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์„ ๋‹ค๋ฃจ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ „ํ†ต์ ์œผ๋กœ ํŒ๋‹ค์Šค๊ฐ€ ์‚ฌ์šฉ๋˜์—ˆ์ง€๋งŒ ์ตœ๊ทผ์—๋Š” ํŒ๋‹ค์Šค์— ๋‹จ์ ์ธ ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Rust๋กœ ์ž‘์„ฑ๋œ ํด๋ผ์Šค๋กœ ๋Œ€์ฒด๋˜์–ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ ฏ๋ธŒ๋ ˆ์ธ์Šค ๋ธ”๋กœ๊ทธ์—์„œ ๊ณต์œ ํ•œ Polars์™€ pandas ๋น„๊ต: ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅผ๊นŒ์š”?๋ฅผ ์ฝ์–ด๋ณด์ž.

Seaborn vs Plotly โ€‹

๋ฐ์ดํ„ฐ ๋ถ„์„์—์„œ ์ฐจํŠธ ์‹œ๊ฐํ™”๋Š” Matplotlib, Seaborn, Plotly ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด Polars DataFrame ์„ Visualizationํ•  ์ˆ˜ ์žˆ๋‹ค.

python
import polars as pl
import plotly.express as px

if __name__ == "__main__":
    df = pl.DataFrame({"category": ["A", "B", "C", "D"], "value": [10, 25, 15, 30]})

    fig = px.bar(
        df, x="category", y="value", title="Polars DataFrame with Plotly Express"
    )
    fig.show()

Released under the MIT License.