Home »
Blog »
AI/ML Engineer সিরিজ » Series 09 » Episode 03
Python Packaging, Config, Logging: notebook code-কে service বানানো
maintainable service কোড (Series 09, Episode 03)
🟡 INTERMEDIATE
Series 09 — Notebook থেকে Production AI
Episode 03 / 09
📑 এই পর্বে যা যা আছে
- ১. গল্প: "এক file-এ ৪০০ লাইন" সমস্যা
- ২. সমস্যা: script বনাম service
- ৩. তিন স্তরে: কেন structure দরকার
- ৪. Package structure — কে কোথায় থাকবে
- ৫. Configuration: hard-code করা বন্ধ করো (pydantic-settings)
- ৬. Secrets: API key কখনো কোডে বা Git-এ নয়
- ৭. Logging:
print() ভুলে যাও
- ৮. structured logging — একটা বাস্তব উদাহরণ
- ৯. Experiment: LOG_LEVEL বদলে দেখো
- ১০. বাংলাদেশের বাস্তব প্রসঙ্গ
- ১১. AI Engineer perspective: 12-factor mindset
- ১২. Boss Question
- ১৩. Job Requirement Decoder: "config & secrets management"
- ১৪. সাধারণ ভুল
- ১৫. Interview Prep
- ১৬. হাতে-কলমে
- ১৭. Project Connection ও পরের পর্ব
🎬 ১. গল্প: "এক file-এ ৪০০ লাইন" সমস্যা
Rahim-এর FastAPI app কাজ করছে। কিন্তু main.py এখন ৪০০ লাইন — model load, preprocessing,
API key, database URL, সব একসাথে। Arif (ML engineer) code review-তে বলল —
"ভাই, তোমার OpenAI API key তো সরাসরি কোডে বসানো, আর তুমি এটা GitHub-এ push করেছ! ওটা এখনই ঘুরিয়ে
দাও (rotate)। আর এই এক file-এ সব — কাল যদি database URL বদলাতে হয়, তোমাকে কোড edit করে আবার deploy
করতে হবে? Debug করার সময় print() দিয়ে খুঁজছ কেন? Production-এ ওই print কোথায় যায় জানো?"
Rahim ঘামছে। আজ আমরা এই তিনটা সমস্যা ঠিক করব — packaging, config, আর logging — যা
একটা script-কে service-grade কোডে রূপ দেয়।
❓ ২. সমস্যা: script বনাম service
| দিক | Script (এখন) | Service (দরকার) |
| Structure | এক file-এ সব | module-এ ভাগ (model, api, config) |
| Config | কোডে hard-coded | environment থেকে আসে |
| Secrets | কোডে/Git-এ | env var / secret store-এ |
| Debugging | print() | structured logging (level সহ) |
| পরিবর্তন | কোড edit + redeploy | শুধু env var বদল |
মূল নীতি: কোড একটাই থাকবে, কিন্তু আচরণ বদলাবে configuration দিয়ে — local, staging,
production সব জায়গায় একই কোড, শুধু ভিন্ন env var।
🧠 ৩. তিন স্তরে: কেন structure দরকার
Level 1 — intuition: এক ঘরে রান্নাঘর, শোবার ঘর, বাথরুম সব একসাথে থাকলে জীবন কঠিন।
আলাদা ঘর থাকলে জিনিস খুঁজে পাওয়া, পরিষ্কার রাখা, মেরামত করা সহজ। কোডেও তেমন — প্রতিটা জিনিসের নিজের জায়গা।
Level 2 — technical: আমরা কোডকে module-এ ভাগ করি (separation of concerns): model loading
এক জায়গায়, preprocessing আরেক জায়গায়, API আলাদা, config আলাদা। ফলে একটা অংশ বদলালে বাকিটা ভাঙে না,
আর test করা সহজ হয়।
Level 3 — AI Engineer perspective: engineer 12-factor app নীতি মানে —
config থাকবে environment-এ, dependency explicit, log stdout-এ, একই কোড সব পরিবেশে। এটা deploy, scale,
আর debug — সব সহজ করে। এই episode সেই ভিত্তি।
📁 ৪. Package structure — কে কোথায় থাকবে
churn-service/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app + routes
│ ├── config.py # settings (env থেকে)
│ ├── schemas.py # Pydantic input/output
│ ├── model.py # model load + predict function
│ └── logging_conf.py # logging setup
├── models/
│ └── model.pkl # saved artifact
├── tests/
│ └── test_predict.py
├── .env # local secrets (Git-এ N:নয়)
├── .env.example # কোন কোন var লাগবে (Git-এ হ্যাঁ)
├── .gitignore # .env, .venv, __pycache__
├── requirements.txt
└── README.md
প্রতিটা file-এর একটা দায়িত্ব। main.py শুধু route জানে; সে model কোথা থেকে আসে তা
model.py-কে জিজ্ঞেস করে; config কোথা থেকে আসে তা config.py জানে।
⚙️ ৫. Configuration: hard-code করা বন্ধ করো
কেন pydantic-settings? কারণ এটা environment variable/.env থেকে config
পড়ে, type check করে, আর একটা জায়গায় centralize করে। Install: pip install pydantic-settings।
# app/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env")
model_path: str = "models/model.pkl"
log_level: str = "INFO"
api_key: str = "" # secret — .env থেকে আসবে
churn_threshold: float = 0.5
# একটাই instance, সবাই import করবে
settings = Settings()
এখন যেকোনো জায়গায়: from app.config import settings → settings.model_path।
Threshold বদলাতে চাইলে কোড না ছুঁয়ে শুধু env var বদলাবে।
🔐 ৬. Secrets: API key কখনো কোডে বা Git-এ নয়
Rahim-এর সবচেয়ে বিপজ্জনক ভুল ছিল কোডে API key রাখা এবং Git-এ push করা। নিয়ম:
# .env (LOCAL — এটা .gitignore-এ থাকবে, কখনো commit নয়)
API_KEY=sk-abc123realsecret
LOG_LEVEL=DEBUG
# .env.example (এটা Git-এ থাকবে — শুধু দেখায় কী কী লাগবে, মান ছাড়া)
API_KEY=
LOG_LEVEL=INFO
# .gitignore
.env
.venv/
__pycache__/
*.pkl
Golden rules: (১) secret কখনো কোডে নয়, env var-এ; (২) .env কখনো Git-এ নয়;
(৩) ভুলে commit করে ফেললে সেই key এখনই rotate করো — Git history থেকে মুছলেও ধরে নাও ফাঁস হয়ে গেছে;
(৪) production-এ secret আসে cloud-এর secret manager বা env var থেকে, file থেকে নয়।
📝 ৭. Logging: print() ভুলে যাও
কেন print() production-এ খারাপ?
- কোনো level নেই — কোনটা info, কোনটা error বোঝা যায় না।
- কোনো timestamp/context নেই — কখন, কোন request-এ ঘটল জানা যায় না।
- বন্ধ/চালু করা যায় না — production-এ hazaar print মানে noise।
Python-এর নিজস্ব logging module এই সব দেয়, বিনামূল্যে:
# app/logging_conf.py
import logging
from app.config import settings
def setup_logging():
logging.basicConfig(
level=settings.log_level, # env থেকে: INFO / DEBUG
format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
)
logger = logging.getLogger("churn-service")
🔧 ৮. structured logging — একটা বাস্তব উদাহরণ
# app/main.py (logging + config + model একসাথে)
from fastapi import FastAPI, HTTPException
from app.config import settings
from app.logging_conf import setup_logging, logger
from app.schemas import Customer, Prediction
from app.model import load_model, predict_one
setup_logging()
app = FastAPI(title="Churn Prediction API")
model = load_model(settings.model_path)
logger.info("Model loaded from %s", settings.model_path)
@app.post("/predict", response_model=Prediction)
def predict(customer: Customer):
try:
risk = predict_one(model, customer)
logger.info("prediction done | risk=%.3f", risk)
return Prediction(
churn_risk=risk,
will_churn=risk >= settings.churn_threshold,
)
except Exception as exc:
logger.exception("prediction failed") # full traceback log করে
raise HTTPException(status_code=500, detail="prediction error")
লক্ষ্য করো: threshold এখন settings থেকে, error logger.exception দিয়ে full
traceback সহ log হচ্ছে, আর client পায় পরিষ্কার একটা 500 error (raw traceback নয় — সেটা security risk)।
🧪 ৯. Experiment: LOG_LEVEL বদলে দেখো
.env-এ LOG_LEVEL=DEBUG দাও, restart করো — অনেক বেশি log দেখবে।
LOG_LEVEL=WARNING দাও — শুধু warning/error দেখবে, info চুপ।
- কোড একটুও বদলাওনি — শুধু config বদলে আচরণ বদলে গেল। এটাই মূল শিক্ষা।
🇧🇩 ১০. বাংলাদেশের বাস্তব প্রসঙ্গ
বাস্তবে অনেক local startup-এ দেখা যায় GitHub-এ ফাঁস হওয়া API key দিয়ে বড় বিল উঠে গেছে, বা কোনো
engineer চলে গেলে config কোথায় আছে কেউ জানে না। একটা fintech বা health app-এ database credential বা
payment key কোডে থাকা মানে বড় নিরাপত্তা ঝুঁকি। তাই এই skill শুধু "সুন্দর কোড" নয় — এটা কোম্পানির টাকা ও
সুনাম বাঁচায়। একজন junior হিসেবে এটা জানা মানে তোমাকে দায়িত্বশীল ধরা হয়।
👷 ১১. AI Engineer perspective: 12-factor mindset
- Config in environment — কোডে নয়, env var-এ।
- Explicit dependencies —
requirements.txt/lock file।
- Logs to stdout — cloud/Docker log নিজে সংগ্রহ করে; file-এ লেখার দরকার নেই।
- Stateless process — কোনো request-এর তথ্য memory-তে জমিয়ে রেখো না; scale করা সহজ হয়।
Must Know / Good to Know / Learn Later: package structure, env config, secrets, basic
logging — Must Know (চাকরির আগেই)। structured JSON logging, log aggregation (ELK) — Good to
Know। distributed tracing, OpenTelemetry — Learn Later (চাকরির পরে)।
💼 ১২. Boss Question
💼 Boss: "কোড তো আগেও চলছিল। এখন এত file, এত সাজানো — এতে আমার ব্যবসার কী লাভ?"
উত্তর: তিনটা সরাসরি লাভ — (১) নিরাপত্তা: secret আর কোডে নেই, তাই ফাঁস
হয়ে বড় বিল বা ডেটা চুরির ঝুঁকি কমল; (২) গতি: কাল threshold বা database বদলাতে হলে
redeploy লাগবে না, শুধু একটা setting বদলাব — ডাউনটাইম কম; (৩) টিমওয়ার্ক: নতুন engineer
এলে কোড বুঝতে ও ঠিক করতে কম সময় লাগবে। মানে কম risk, কম খরচ, দ্রুত পরিবর্তন।
🔎 ১৩. Job Requirement Decoder: "Configuration & secrets management, clean code"
- কী বোঝায়? config env-এ রাখা, secret নিরাপদে সামলানো, কোড module-এ পরিষ্কার ভাগ করা।
- কেন চায়? নিরাপত্তা, maintainability ও নির্ভরযোগ্য deploy-এর জন্য।
- কোন সমস্যা সমাধান করে? ফাঁস হওয়া secret, "কোড edit করে redeploy", spaghetti code।
- Junior-এর কী জানা লাগে?
.env + pydantic-settings, .gitignore,
Python logging, module structure।
- এখনই কী master লাগে না? Vault, KMS, dynamic secret rotation, feature flag system — পরে।
- GitHub-এ কীভাবে দেখাবে? পরিষ্কার package structure,
.env.example
(secret ছাড়া), README-তে "কীভাবে config করবে"।
- Interview-তে কী জিজ্ঞেস করতে পারে? "secret কোথায় রাখো?", "
print বনাম
logging?", "একই কোড তিন পরিবেশে চালাও কীভাবে?"
⚠️ ১৪. সাধারণ ভুল
ভুল ১: secret কোডে/Git-এ। → env var + .gitignore; ফাঁস হলে rotate।
ভুল ২: debug করতে print()। → logging level সহ।
ভুল ৩: error-এ client-কে full traceback দেখানো। → log-এ রাখো, client-কে generic message।
ভুল ৪: config নানা জায়গায় ছড়ানো। → একটা config.py-তে centralize।
ভুল ৫: .env.example না রাখা। → নতুন dev বুঝবে না কী কী var লাগবে।
🎤 ১৫. Interview Prep
প্রশ্ন ১: "API key/secret কীভাবে manage করো?"
উত্তর: env var/.env (gitignored) locally, production-এ secret manager; কোডে কখনো নয়; ফাঁস হলে rotate।
প্রশ্ন ২: "print আর logging-এর পার্থক্য?"
উত্তর: logging-এ level, timestamp, context, on/off control থাকে; print production-এ noise ও অনিয়ন্ত্রিত।
প্রশ্ন ৩: "একই কোড dev ও prod-এ ভিন্ন আচরণ করবে কীভাবে?"
উত্তর: environment variable দিয়ে config আলাদা; কোড এক থাকে (12-factor)।
প্রশ্ন ৪: "কেন কোড module-এ ভাগ করো?"
উত্তর: separation of concerns — test, maintain, ও পরিবর্তন সহজ হয়।
✍️ ১৬. হাতে-কলমে
Mini exercise:
১. তোমার E02-এর FastAPI app-কে উপরের structure-এ ভাগ করো (config, schemas, model, main)।
২. pydantic-settings দিয়ে churn_threshold ও log_level env থেকে পড়াও।
৩. .env, .env.example ও .gitignore বানাও; নিশ্চিত করো .env ignore হচ্ছে।
৪. সব print() মুছে logging ব্যবহার করো; LOG_LEVEL বদলে পার্থক্য দেখো।
৫. একটা fake secret দিয়ে check করো git status-এ .env দেখাচ্ছে কিনা (দেখানো উচিত নয়)।
🚀 ১৭. Project Connection ও পরের পর্ব
আমাদের flagship "Bangladesh Tech Career Assistant"-এর API এখন একটা পরিষ্কার package।
LLM/embedding API key এখন .env-এ নিরাপদ, threshold config-এ, আর সব কিছু log হচ্ছে।
✓ package structure, ✓ env config (pydantic-settings), ✓ secrets নিরাপদে, ✓ structured logging —
এখন কোড service-grade।
পরের episode-এ আমরা এই API-কে নিরাপদ ও দ্রুত করব — API key দিয়ে authentication,
response caching, আর rate limiting-এর ধারণা। মানে যে কেউ যেন যা খুশি call করতে না পারে, আর একই প্রশ্নে
বারবার model না চালিয়ে দ্রুত উত্তর দিতে পারি।