- 모든 .md, .html 파일 권한을 644로 정상화 - .gitignore 파일 권한도 644로 수정 - 문서 파일에 실행 권한은 불필요하고 보안상 바람직하지 않음 - deprecated 아이디어 폴더 생성 및 레벨별 UI 변경 아이디어 이동
9.2 KiB
9.2 KiB
tags, date
| tags | date |
|---|---|
| 함수형프로그래밍, 적용가이드, 순수함수, 실전전략, 로빙시스템 | 2025-07-04 |
함수형 프로그래밍 적용 가이드라인
요약
로빙 프로젝트에서 함수형 프로그래밍을 실전 적용할 때의 구체적인 기준과 가이드라인을 제시합니다. 각 구성요소별 순수 함수 가능성을 수치화하여 실용적인 적용 전략을 제공합니다.
1. 함수형 적용 원칙
기본 철학
- 점진적 도입: 한 번에 모든 것을 바꾸지 않고 단계별 전환
- 실용적 균형: 이론적 완성도보다 팀 생산성과 코드 안정성 우선
- 명확한 경계: 순수 함수 영역과 부작용 영역의 명확한 분리
전체 프로젝트 권장 비율
함수형 40% : 명령형 60%
| 영역 | 함수형 권장 비율 | 이유 |
|---|---|---|
| 데이터 변환 로직 | 80-100% | 가독성, 재사용성, 테스트 용이 |
| 비즈니스 로직 | 50-70% | 추상화 효과, 단 과도하면 이해도 저하 |
| 상태 변경/IO | 0-20% | 명령형이 더 명확하고 디버깅 쉬움 |
2. 로컬 개발과 서버 테스트 전략
2.1 개발 환경의 현실적 제약
로빙 시스템은 분산 아키텍처로 설계되어 로컬에서 전체 실행이 불가능합니다:
| 구분 | 로컬 환경 | 서버 환경 |
|---|---|---|
| 순수 함수 | ✅ 테스트 가능 | ✅ 테스트 가능 |
| 외부 서비스 | ❌ 접근 불가 | ✅ 모두 연결 |
| 데이터베이스 | ❌ 서버 데이터 | ✅ 실제 데이터 |
| 스킬 서비스 | ❌ 포트 8015 없음 | ✅ skill-embedding 실행 |
2.2 함수형 프로그래밍의 장점 활용
로컬에서 테스트 가능한 영역:
# ✅ 순수 함수들 - 외부 의존성 없음
from app.llm.mistral import create_intent_analysis_prompt
from app.core.memory.scoring import calculate_time_decay
from app.core.emotion import EmotionState
# 모듈별 단위 테스트
prompt = create_intent_analysis_prompt("안녕하세요")
decay = calculate_time_decay(3600) # 1시간
emotion = EmotionState(valence=0.5, arousal=0.3)
서버에서만 테스트 가능한 영역:
# ❌ I/O 함수들 - 외부 서비스 필요
- ChromaDB 쿼리 (서버 persistent storage)
- skill-embedding:8015 (79MB ONNX 모델)
- Gemini/Mistral API (API 키 필요)
- Slack 웹훅 (실제 워크스페이스)
2.3 올바른 개발 워크플로우
graph LR
A[로컬 개발] --> B[모듈 테스트]
B --> C[Git Push]
C --> D[Gitea Actions]
D --> E[서버 배포]
E --> F[통합 테스트]
- 로컬 개발: 코드 작성, 문법 검증, 모듈 테스트
- Push: Git 커밋, Gitea에 푸시
- 서버: 자동 배포, 통합 테스트, 실제 작동 확인
2.4 아키텍처 설계 의도
왜 이렇게 설계했는가?
- 로빙은 가벼운 본체: 118MB 메모리만 사용
- 스킬은 공유 서비스: 100개 로빙이 1개 스킬 서비스 공유
- 확장성 우선: 로빙 수가 늘어도 스킬 서비스는 하나
이것이 바로 함수형 아키텍처의 핵심입니다:
- 테스트 가능한 작은 단위
- 외부 의존성 최소화
- 명확한 경계 분리
3. 로빙 구성요소별 순수 함수 가능성 분석
상세한 구성요소별 분석과 코드 예시는 로빙 존재와 함수형 프로그래밍 문서를 참조하세요.
요약
- 스킬 시스템: 77% 순수 함수 가능 → 우선 적용 영역
- 스탯 시스템: 60% 순수 함수 가능 → 계산 중심부터 적용
- 아이템 시스템: 32% 순수 함수 가능 → 명령형 유지
4. 핵심 모듈별 가이드라인
3.1 기억 모듈 (65% 순수)
# ✅ 순수 함수: 저장 우선도 판단
def calculate_memory_priority(content: str, keywords: List[str], user_context: Dict) -> float:
"""기억 저장 우선도 계산"""
keyword_score = sum(1 for keyword in keywords if keyword in content.lower())
length_score = min(len(content) / 1000, 1.0)
context_score = user_context.get('importance_multiplier', 1.0)
return min(1.0, (keyword_score * 0.4 + length_score * 0.3) * context_score)
# 🔄 부작용 분리: 실제 저장
async def store_memory_if_important(user_id: str, content: str, context: Dict) -> bool:
priority = calculate_memory_priority(content, ['중요', '프로젝트'], context)
if priority > 0.7:
await save_to_chroma_db(user_id, content, priority)
return True
return False
3.2 감정 모듈 (70% 순수)
# ✅ 순수 함수: 감정 분석
def analyze_emotion_vector(text: str) -> Dict[str, float]:
"""감정 벡터 계산"""
emotion_keywords = {
'joy': ['기쁨', '행복', '좋아', '만족'],
'anger': ['화나', '짜증', '분노', '불만'],
'sadness': ['슬픔', '우울', '아쉬움'],
'fear': ['걱정', '불안', '두려움']
}
emotion_scores = {}
for emotion, keywords in emotion_keywords.items():
score = sum(1 for keyword in keywords if keyword in text) / len(keywords)
emotion_scores[emotion] = min(1.0, score)
return emotion_scores
# 🔄 상태 반영: 감정 히스토리 업데이트
async def update_emotion_history(user_id: str, text: str) -> Dict[str, float]:
current_emotions = analyze_emotion_vector(text)
await save_emotion_log(user_id, current_emotions, datetime.now())
return current_emotions
3.3 윤리 모듈 (60% 순수)
# ✅ 순수 함수: 윤리 위반 판단
def check_ethical_violations(content: str, policies: List[str]) -> List[str]:
"""윤리 정책 위반 검사"""
violations = []
sensitive_patterns = [
(r'개인정보.*공유', '개인정보 보호 위반'),
(r'비밀.*유출', '기밀 정보 유출'),
(r'허위.*정보', '허위 정보 유포')
]
for pattern, violation_type in sensitive_patterns:
if re.search(pattern, content):
violations.append(violation_type)
return violations
# 🔄 정책 적용: 실제 차단 처리
async def enforce_ethical_policy(user_id: str, content: str) -> bool:
violations = check_ethical_violations(content, await get_user_policies(user_id))
if violations:
await log_violation(user_id, violations, content)
return False # 차단
return True # 허용
5. 실전 적용 전략
4.1 함수형 우선 적용 영역
- 데이터 변환 스킬 (Thread Digest, Action Extractor)
- 계산 중심 스탯 (연산, 공감)
- 분석 모듈 (감정 분석, 윤리 검사)
4.2 명령형 유지 영역
- 외부 API 연동 (Slack, Gmail, Notion)
- 실시간 반응 (알림, 이벤트 처리)
- 상태 변경 (DB 저장, 설정 변경)
4.3 혼합 접근 패턴
# 권장 패턴: 순수 함수 + 오케스트레이터 분리
async def skill_orchestrator(input_data, user_id):
"""스킬 실행 오케스트레이터"""
try:
# 1. 순수 계산
result = pure_skill_function(input_data)
# 2. 부작용 처리
await save_result(user_id, result)
await update_stats(user_id, calculate_stat_change(result))
await send_notification(user_id, format_response(result))
return SkillExecutionResult.success_result(result)
except Exception as e:
return SkillExecutionResult.error_result(str(e))
6. 판단 기준 체크리스트
✅ 함수형 적용 가능 신호
- map, filter, reduce로 로직이 간결해진다
- 디버깅 없이도 결과를 바로 예측할 수 있다
- 중간 단계가 없고 한 방향 흐름이다
- 같은 입력에 항상 같은 출력이 나온다
- 외부 상태에 의존하지 않는다
❌ 함수형 피해야 할 신호
- 중간값을 계속 찍어봐야 한다
- 사이드 이펙트가 많다 (파일, 네트워크 등)
- 팀원이 "이게 뭐 하는 건데?"라고 묻는다
- 시간이나 외부 상태에 따라 결과가 달라진다
- 에러 처리가 복잡하다
7. 성공 지표
개발 생산성
- 테스트 커버리지: 순수 함수 스킬 90% 이상
- 버그 발생률: 함수형 적용 영역 50% 감소 목표
- 코드 리뷰 시간: 순수 함수 부분 30% 단축
시스템 안정성
- 에러 격리: 한 스킬의 실패가 전체 시스템에 영향 없음
- 성능 유지: 함수형 적용 후에도 응답 시간 3초 이내 유지
- 확장성: 새로운 스킬 추가 시 기존 코드 영향 최소화
결론
로빙의 함수형 프로그래밍 도입은 스킬 중심의 점진적 적용이 가장 효과적입니다. 순수성이 높은 스킬(77%)부터 시작하여, 계산 중심 스탯, 분석 모듈 순으로 확장하되, IO 중심의 아이템은 명령형을 유지하는 것이 실용적입니다.
핵심 원칙: "완벽한 함수형보다는 안정적이고 확장 가능한 혼합 아키텍처"
이를 통해 로빙은 예측 가능하고 테스트 가능한 디지털 존재로 성장할 수 있습니다.