AI 에이전트 시스템의 핵심, A2A와 MCP

A2A와 MCP: AI 에이전트 시스템의 미래를 이끌 핵심

최근 하루가 멀다하고 발전하고 있는 인공지능(AI) 에이전트와 대규모 언어 모델(LLM)은 소프트웨어 개발의 새로운 장을 계속 써내려 가고 있다. 이러한 변화의 선단에는 A2A(Agent-to-Agent) 프로토콜MCP(Model Context Protocol)라는 두 가지 핵심 기술이 포진해 있다. 이들은 서로 다른 지향점을 가지고 있지만 함께 적용될 때 다중 에이전트 시스템에서 엄청나게 큰 시너지를 발휘할 수 있으며 AI 에이전트가 자율적인 실행과 협업을 구현하는 근간이 된다.

 

 

1. A2A와 MCP의 관계 및 역할: 상호 보완적인 AI 통신 프로토콜

요즘 가장 핫한 A2A와 MCP는 경쟁 관계가 아닌 수평-수직 보완 관계에 있다고 볼 수 있다. 두 프로토콜 모두 JSON-RPC 2.0HTTP+SSE(Server-Sent Events)를 전송 방식으로 사용하고 있으며 주요한 특징은 다음과 같다.

  • A2A (Agent-to-Agent)

    • 정의/목적: A2A는 서로 다른 AI 에이전트 간의 협업 및 작업 분배를 표준화하는 프로토콜로서 AI 에이전트 간의 직접적인 통신과 협력을 가능하게 하는, Google이 2025년 4월에 도입한 개방형 표준이다.
    • 핵심 구조 및 기능: Agent Card, Task, Artifact, SSE 스트림으로 구성되며, 에이전트들이 서로를 발견하고, 작업을 위임하며, 실시간 업데이트를 스트리밍하여 복잡한 프로세스를 조율할 수 있도록 지원한다. 이는 느슨한 결합, 모달 혼합, 장기 작업에 최대의 강점을 가진다.
    • 한계: A2A 자체로는 외부 리소스 직접 호출 기능이 없다.
    • 역할: 에이전트 조직도를 설계하고 에이전트 간 통신과 협력, 정보 교환 및 작업 위임을 담당하는 ‘가로 축’ 또는 ‘팀 코디네이터’ 역할을 한다.
  • MCP (Model Context Protocol)

    • 정의/목적: MCP는 각 에이전트가 외부 도구 및 데이터를 안전하게 호출하는 방식을 표준화하는 프로토콜로서 Anthropic이 2024년 11월에 발표한 개방형 표준이며 OpenAI, Google DeepMind 등 주요 AI 기업들이 다수 채택하고 있다.
    • 핵심 구조 및 기능: Server, Client, Tool, JSON Schema I/O로 구성되며, AI 모델, 특히 LLM이 외부 데이터 소스와 도구에 연결되는 방식을 표준화하여 에이전트가 작업을 수행하는 데 필요한 컨텍스트와 기능을 제공한다. 이는 타입 안전성, 표준 함수 호출, 컨텍스트 공유에 강점이 있으며 AI 모델이 외부 시스템에 직접 연결되어 정보를 가져오거나 기능을 실행할 수 있도록 지원한다.
    • 한계: MCP에는 다중 에이전트 조정 로직이 없다.
    • 역할: 각 노드(에이전트)에 필요한 외부 능력을 연결하고 에이전트와 외부 Tool/DB 연결, 맥락 및 기능 제공을 담당하는 ‘세로 축’ 또는 ‘도구 상자’이자 ‘컨텍스트 제공자’ 역할로서 종종 AI 시스템의 ‘사서이자 보안 요원’으로 비유되기도 한다.

 

A2A - MCP

< A2A-MCP 협업 아키텍처 >

 

 

2. 시너지를 위한 협업 방법: 다중 에이전트 시스템의 강화

A2A와 MCP를 함께 사용하면 다중 에이전트 시스템(여러 개의 지능형 에이전트가 상호 작용하여 협력 또는 경쟁을 통해 복잡한 문제를 해결하거나 문제를 달성하는 시스템)에서 역할 분담은 A2A로, 능력 확장은 MCP로 분리되어 설계, 보안, 스케일이 쉬워진다. 이들은 ‘수직 통합(MCP)과 수평 통합(A2A)의 결합’을 통해 다수의 에이전트, LLM, 그리고 다양한 컨텍스트 소스가 모두 협력해야 하는 시스템 구축의 핵심 과제를 해결할 수 있는 방안을 제시한다.

  • 시너지 구조 설계 방법:
    1. 오케스트레이터 에이전트: 사용자 요청을 수신하여 하위 작업으로 분해하고 A2A Task로 전송한다. 필요 시 Agent Card를 조회, 적합한 전문 에이전트를 선택한다.
    2. 전문 에이전트: 수신된 Task를 처리하는 중 외부 검색, RAG(Retrieval-Augmented Generation: 검색 증강 생성), DB 쿼리 등 도구 호출이 필요하면 자체 MCP Client로 연결한다. 도구 결과를 Artifact로 래핑하여 A2A 답신을 보낸다.
    3. MCP 서버: GitHub, Slack, Postgres, 사내 ERP 등 각종 리소스를 JSON Schema로 노출하고 MCP가 타입 검증을 수행하여 에이전트-도구 간 계약을 유지한다.
  • 협업 최적화 팁:
    • Agent Card 설계: skills 키에 MCP tool capability 태그를 작성, 오케스트레이터가 도구 사용 가능 여부를 빠르게 판단할 수 있도록 한다.
    • Task chunking: 장기 작업은 A2A sendSubscribe를 통해 진행 상황 스트림을 받아 UX 체감을 개선할 수 있다.
    • Schema version 관리: MCP Tool JSON Schema에 version 필드를 포함하여 에이전트가 호환성 체크 후 호출하도록 한다.
    • Fallback 전략: MCP 서버 장애 시 동일 Tool API를 노출하는 대체 서버를 Agent Card에 다중 등록하여 자동 Failover를 구현할 수 있다.
  • 보안 및 감사: A2A는 에이전트 간 OAuth 스코프를 분리하고 MCP는 데이터 소스별 API Key를 분리하여 최소 권한 원칙을 따른다. 또한 Task/Artifact 로그를 중앙에서 수집하여 추적성을 확보한다.
  • 기대 효과: 전문성 분산, 보안 분할, 개발 속도 개선을 통해 모듈형, 확장 가능하며 협업적인 AI 시스템을 구축할 수 있는데 예를 들면 핸즈프리 간편결제 서비스에서 확장성과 파트너 연동 속도를 동시에 달성하는 데 중요하다.




 

3. 개발자 입장에서의 구현 방법

A2A와 MCP는 모두 HTTP, JSON-RPC, SSE 등 널리 채택된 웹 표준을 기반으로 구축되었으며 모듈형 설계 철학을 통해 구성 요소를 독립적으로 개발, 배포, 업데이트할 수 있다. 또한 엔터프라이즈급 보안이 기본적으로 내장되어 있다.

  • Google의 Agent Development Kit (ADK) 활용: ADK는 A2A와 MCP를 모두 지원하며, 에이전트를 구축하는 데 필요한 구성 요소, 라이브러리, 스캐폴딩을 제공한다.

    1. 시스템 설계 및 에이전트 구현: 필요한 에이전트와 각 에이전트의 역할을 정의, ADK를 사용해 에이전트를 구현한다.
    2. MCP 설정 및 통합: MCP 서버 설정 또는 기존 서버를 활용하여 데이터와 도구에 접근할 수 있도록 한다. FastMCP 라이브러리를 사용해 MCP 서버를 생성하고 @calculator_mcp.tool( )과 같은 데코레이터로 도구를 정의할 수 있다. 또 MCPToolset 클래스를 사용해 MCP 서버에 연결하고 필요한 도구를 에이전트에 추가할 수 있다.
    3. A2A 통신 설정: 에이전트 간 통신 채널을 구성하여 정보 교환과 조율을 가능하게 한다. Agent Card를 게시하여 메타 데이터 및 기능을 노출하고 작업을 시작하고 메시지 및 Artifact를 관리한다.
    4. 테스트 및 배포: 시스템이 원활히 작동하는지 테스트하고 필요에 따라 Google Cloud의 Vertex AI Agent Engine을 통해 배포한다. Azure App Service와 같은 클라우드 플랫폼도 A2A 애플리케이션 배포에 적합하다.

 

  • Python 예시:

# A2A 클라이언트: 특정 에이전트에 Task 전송
import requests, json, sseclient

agent_card = requests.get(“https://agent.example.com/.well-known/agent.json”).json()
task = {“title”: “generate sales chart”, “input”: {“period”:”Q2″}}
resp = requests.post(agent_card[“endpoint”]+”/tasks/send”, json=task,
headers={“Authorization”: f”Bearer {TOKEN}”})
task_id = resp.json()[“id”]

# 진행 상황 실시간 수신
stream = sseclient.SSEClient(f'{agent_card[“endpoint”]}/tasks/{task_id}/events’,
headers={“Authorization”: f”Bearer {TOKEN}”})
for event in stream:
print(event.data)

# MCP 클라이언트: 외부 DB 쿼리
mcp_req = {
“tool”: “postgres.query”,
“args”: {“sql”: “SELECT * FROM orders WHERE quarter=’Q2′;”}
}
mcp_resp = requests.post(“http://mcp.local/query”, json=mcp_req).json()
rows = mcp_resp[“result”]

    • A2A 클라이언트 (Task 전송 및 진행 상황 수신): 에이전트 카드의 엔드포인트에 Task를 JSON 형식으로 전송하고 Task ID를 통해 SSE 스트림으로 실시간 진행 상황을 수신한다.
    • MCP 클라이언트 (외부 DB 쿼리): mcp_req에 도구(tool)와 인자(args)를 정의하여 MCP 서버에 요청을 보내고, 결과를 mcp_resp로 받는다.
    • A2A는 Task ID로 스트리밍하고 MCP는 함수 호출-결과 패턴을 따른다.

 

 

4. 다양한 산업에서의 활용

A2A와 MCP의 시너지 효과는 다양한 산업 및 실제 시나리오에서 복잡한 엔터프라이즈 워크플로우를 혁신하는 데 활용될 수 있으며 아래는 그 몇 가지 예이다.

  • 전자상거래: 추천 Agent, 재고 Agent, 배송 Agent가 A2A를 통해 협의하여 맞춤 거래를 생성하면 각 Agent는 MCP를 통해 가격/재고 DB, 물류 API를 호출하여 맞춤 오퍼를 제공하고 재고 오차를 줄인다.
  • 핀테크(간편결제): 결제 Agent, KYC Agent, 리스크 Agent가 A2A Task 체인으로 연결되고 결제 Agent는 MCP를 통해 POS/BLE SDK를, 리스크 Agent는 Fraud DB를 호출하여 결제 승인 시간 단축 및 사기 감소 효과를 얻는다.
  • 제조: MES Agent가 품질 Agent, 부품 Agent와 A2A로 조율하고, 부품 Agent는 MCP 서버를 통해 ERP에서 BOM을 조회하여 생산 지연을 최소화한다.
  • 헬스케어: 주치의 Agent가 보험 Agent, 약국 Agent에 A2A로 처방 작업을 배분하고, 각 Agent는 MCP를 통해 EHR(전자의무기록) 및 약국 재고 API를 호출하여 환자 대기 시간을 줄인다.
  • 대출 신청 처리: 대출프로세서 에이전트가 MCP를 사용하여 신용 점수 API 호출, 은행 거래 내역 검색, OCR을 통한 문서 검증을 수행한다. 검증된 데이터가 확보되면 에이전트는 A2A를 사용하여 위험평가 에이전트, 규정준수 에이전트, 지출 에이전트 등과 협력하여 대출 평가 및 실행을 진행한다.
  • 여행 관리 시스템: 여행관리 Agent가 오케스트레이터 역할을 하여 사용자 요청을 분석하고 작업을 환율 에이전트, 액티비티 에이전트 등 전문 에이전트에게 A2A로 위임한다. 각 전문 에이전트는 MCP를 통해 실시간 환율 API, 예산 친화적 추천 데이터를 가져와 포괄적인 여행 계획을 제공한다.
  • 고객 서비스 시스템: 청구, 기술 지원 등 다양한 영역의 에이전트가 A2A로 협력하여 고객 문제를 해결하고, MCP를 통해 고객 데이터와 지식 기반에 접근한다.
  • 데이터 분석 파이프라인: 데이터 정리, 특징 추출, 모델 학습 등 각 단계의 에이전트가 A2A로 데이터를 주고받고, MCP를 통해 데이터 저장소와 계산 자원에 접근하여 대규모 데이터 처리 작업을 자동화한다.
  • 기업 내부 데이터 처리: 한 에이전트가 MCP를 통해 기업 내부 데이터에 접근하고, A2A를 통해 다른 에이전트에게 그 정보를 전달하거나 작업을 위임할 수 있다.
  • 온보딩 워크플로우 자동화: HR, IT, 시설 관리 등 여러 부서가 관련된 복잡한 신규 직원 온보딩 프로세스를 A2A 프로토콜을 통해 각 부서 에이전트가 협력하고, 다수의 다중 에이전트 시스템이 전체 워크플로우를 조정하여 자동화한다.

 

A2A와 MCP는 AI 에이전트 시스템에서 서로 보완적인 역할을 수행하며, 함께 사용될 때 더욱더 강력한 시너지를 발휘하여 AI 시스템의 모듈성, 상호 운용성 및 효율성을 극대화할 수 있다. A2A는 에이전트 간의 통신과 협업을, MCP는 에이전트와 외부 데이터 및 도구 간의 연결을 담당하며 개발자들은 Google의 ADK와 같은 프레임워크를 활용하여 이 두 프로토콜을 구현할 수 있고, 이를 통해 여행 계획, 고객 서비스, 데이터 분석 등 다양한 실제 문제 해결에 기여할 수 있다. 이 두 프로토콜은 AI 시스템이 단순히 정보를 처리하는 것을 넘어, 적극적으로 상호 작용하고, 협력하며, 실제 컨텍스트를 기반으로 행동하는 ‘에이전트 웹(Agent Web)’의 출현을 촉진하고 있다. 이는 통합 복잡성을 줄이고, 운영 효율성을 향상시키며, 거버넌스를 개선하고, 혁신을 가속화하며, 미래에 대비할 수 있는 AI 투자를 이끌어 내고 있다.

새로운 AI 기반 소프트웨어 개발: MCP와 바이브 코딩

최근 너무나도 빠른 AI의 발전은 전통적인 소프트웨어 개발 패러다임을 근본적으로 재편하고 있다. 이는 단순한 자동화를 넘어 개발자의 역활과 역량, 개발팀의 협업 방식, 프로젝트 관리 방식, 그리고 코드 자체가 구상되고 생성, 구현되는 방식에까지 그 막대한 영향을 미치고 있는데 이러한 변화의 중심에는 새로운 AI 기반 소프트웨어 개발인 MCP와 바이브 코딩이라는 두 가지 개념이 있다. 아직은 시기상조라고, 사람을 따라오기에는 멀었다고 말하곤 하지만 그 발전 속도와 어떻게 활용하느냐는 다른 문제인 것이다. 이에 많은 관심을 받고 있는 이 기술은 무엇이고 핵심적인 특징과 더불어 상호 간 어떻게 작용하며 앞으로 소프트웨어 개발의 미래를 이끌어갈지 살펴보고자 한다.

 

1. MCP: AI를 위한 표준화된 연결 인프라

MCP(Model Context Protocol)는 대규모 언어 모델(LLM)과 같은 AI 시스템이 외부 데이터 소스나 도구(문서, 데이터베이스, API, 파일 시스템 등)와 표준화된 방식으로 연동할 수 있도록 돕는 오픈 프로토콜이다. 이는 2024년 미국의 생성형 인공지능 서비스개발 업체인 앤스로픽(Anthropic)에서 발표한 프로토콜로 OpenAI, Google DeepMind 등과 같은 주요 AI 기업들이 빠르게 채택하면서 AI 에이전트 시대의 개방형 표준으로 자리 잡아가고 있다. 쉽게 이야기해서 MCP는 AI 시스템의 USB-C 포트와 같은 역할로 다양한 데이터 소스와 도구에 AI 모델을 연결하는 표준화된 방법을 제공한다.

✔️ MCP 주요 특징 및 원칙

  • 기술적 구조: JSON-RPC 2.0 기반 메시지 구조를 사용하여 요청과 응답을 표준화하고 MCP 서버(데이터/기능 노출)와 클라이언트(AI 앱/IDE 내장) 구조를 가진다. 이는 상태 기반 연결 관리를 통해 효율적인 통신을 가능하게 해준다.
  • 핵심 철학: MCP의 핵심은 단순한 데이터 교환을 넘어 모든 상호 작용에서 풍부하고 의미 있는 컨텍스트 이해를 유지하는 데 있다. 이에 대한 주요 원칙으로는 컨텍스트 무결성 (정보의 의미론적인 의미 보존), 모듈식 유연성 (AI 시스템 재설계 없이 적응/확장 가능), 보안 및 거버넌스 (제어되고 감사 가능한 AI 상호 작용 메커니즘 의무화) 등이 있다.
  • 주요 기능: 데이터 수집, 변환, 컨텍스트 메타데이터 태그 지정 및 다양한 플랫폼 전반의 AI 상호 운용성을 위한 포괄적인 프레임워크를 정의하여 표준화된 통합을 지원한다. 또한 개발자가 MCP 서버를 통해 데이터를 노출하거나 AI 애플리케이션을 개발하도록 개발자 역량 강화를 지원하고 다중 도구 에이전트 워크플로우자연어 데이터 액세스 (예를 들어 AI2SQL 등)를 가능하게 한다.
  • 채택 및 적용: VS Code, Cursor, Replit 등 여러 통합 개발 환경(IDE) 및 코딩 플랫폼에서 AI 코딩 도우미에게 실시간 프로젝트 컨텍스트를 제공하기 위해 MCP를 채택했다. 또한 프로젝트 관리, 헬스케어, 전자상거래 등 다양한 산업 분야에서 정보 silo 문제를 해결하고 컨텍스트 기반 AI 시스템을 구축하는 데 활용되고 있다.
  • 보안 고려 사항: MCP는 견고한 설계에도 불구하고 프롬프트 주입, 도구 권한 및 데이터 유출, 유사 도구와 같은 보안 문제가 제기될 수 있는데 이는 개방성과 동적 생태계의 복잡성으로 인해 발생하기 때문에 지속적인 경계와 강력한 보안 감사가 필수적이다.

MCP Architecture

※ “What Is the Model Context Protocol (MCP) and How It Works”, descope.com, April 7, 2025

 

2. Vibe Coding: AI와 함께하는 대화형 소프트웨어 개발

바이브 코딩은 2025년 초 컴퓨터과학자인 안드레아 카르파티(Andrej Karpathy)가 대중화한 AI 지원 소프트웨어 개발 방식으로 개발자가 직접 코드를 작성하기보다 LLM에 자연어로 의도를 전달하고, AI가 코드를 생성하는 혁신적인 프로그래밍 방식을 의미한다. 이는 인간 개발자와 코딩에 특화된 LLM이 마치 애자일의 페어 프로그래머처럼 동적인 대화형 루프 내에서 협력하는 것이 주된 특징인데 이와 유사한 노코드(No-code)는 GUI를 통해 프로그래밍 지식이 없더라도 개발을 가능하게 하는 방식으로 코딩없이도 비전문가가 직접 웹, 앱서비스 등을 구축할 수 있는, AI와는 직접적인 관련이 없다는 것이 다른 점이다.

✔️ 바이브 코딩의 주요 특징 및 철학

  • “무엇(What)”과 “어떻게(How)”의 분리: 개발자는 ‘무엇을’ 원하는지 설명하고 ‘어떻게’ 구현할지는 AI가 담당한다. Karpathy는 이를 “코드가 존재한다는 사실을 잊고, 분위기에 완전히 몰입하며, 기하급수적인 발전을 수용한다”고 말한다.
  • 바이브(느낌) 중심: “깔끔하게”, “사용자 친화적으로”, “부드럽게”와 같은 추상적 표현을 AI가 이해하고 코드로 변환할 수 있는데, 한 번의 명령이 아닌 대화를 통한 점진적 개선을 추구하고 있다.
  • 개발자 역할 변화: 전통적인 프로그래머는 모든 코드를 수동으로 작성하는 대신, AI를 안내하고, 생성된 출력을 테스트하며, 개선을 위한 목표화된 피드백을 제공하는 역할로 전환된다. 개발자가 모두 사라지는 것이 아닌 역할이 변경되고 거기서 또다른 역할을 찾아 수행할 수 있으며 전문화된 고급개발자들은 오히려 더 필요해질 수 있다.
  • 장점:
    • 낮은 진입 장벽: 비기술적 배경을 가진 사람들도 소프트웨어 개발을 쉽게 할 수 있다.
    • 빠른 프로토타이핑: 애플리케이션 초기 버전을 단기간에 빠르게 생성하여 아이디어를 신속하게 테스트하고 피드백을 지속적으로 얻을 수 있다.
    • 효율성: 반복적이고 지루한 프로그래밍 작업을 AI가 자동화하여 개발자가 고부가가치 활동에 집중할 수 있도록 한다.
    • 혁신 및 실험: 기술적 세부 사항에 대한 인지 부하를 줄여 더 큰 실험 정신을 촉진하고, 새로운 아이디어를 보다 쉽게 시도하고 테스트할 수 있다.
    • 학습 도구: AI가 생성한 코드를 관찰하고 수정하며 새로운 언어와 기술을 빠르게 학습하는 효과적인 방법으로 활용될 수 있다.
  • 단점:
    • 코드 품질 문제: AI가 생성한 코드는 비효율적이거나 이해하기 어렵고, 향후 유지보수가 어려울 수 있다.
    • 보안 위험: AI 도구가 중요한 보안 조치를 간과할 수 있어 애플리케이션이 취약해질 수 있다. 생성코드를 그대로 사용함에 위험성이 존재한다.
    • AI에 대한 과도한 의존: 기본적인 코딩 기술 개발을 저해하고, 심층적인 이해 없이 코드 작동 방식을 수용할 경우 문제 해결에 어려움을 겪을 수 있다.
    • 제한된 사용자 정의: 특정하거나 복잡한 요구 사항에는 어려움을 겪을 수 있으며, 상당한 수동 개입이 필요할 수 있다.
    • 오류 발생 가능성: 비전문가도 기능적인 소프트웨어를 생성할 수 있지만, 결과는 종종 제한적이고 오류가 발생하기 쉽다.

Vibe coding

※ “What Is Vibe Coding And Can It Replace Traditional Coding?”, northcoders.com, 2025




3. MCP와 바이브 코딩의 시너지: 컨텍스트 기반 개발의 가속화

이처럼 겉보기에는 MCP와 바이브 코딩은 별개의 영역처럼 보이지만 한 발짝 뒤로 물러나 보면 매우 상호 보완적이며 강력한 시너지를 창출할 수 있다. 바이브 코딩이 LLM의 생성 능력을 활용하여 빠르고 즉흥적인 코드 생성을 가능하게 한다면, MCP는 AI가 실제 업무 환경의 복잡한 시스템과 데이터에 접근할 수 있게 하는 표준화된 연결 방식을 제공하기 때문이다. 바이브 코딩으로 생성된 코드의 궁극적인 품질과 유용성은 LLM에 제공되는 컨텍스트의 풍부함, 정확성 및 포괄성에 달려 있으며, MCP는 바로 이러한 종류의 풍부하고 안전하며 정확한 컨텍스트(맥락, 환경이나 각종 상황 등) 정보를 AI 시스템에 관리, 표준화 및 전달하도록 설계한다.

✔️ 주요 시너지 효과 및 활용 방안

  • 향상된 컨텍스트 바이브 코딩: MCP 서버를 통해 LLM에 대내외 환경, 비즈니스 요구 사항, 기술 제약 및 문제점, 기존 코드 베이스 상태, 아키텍처 결정 등 풍부하고 실시간적이며 구조화된 프로젝트 컨텍스트를 제공한다. 이를 통해 AI는 조직의 Best Practice를 준수하는 고품질의 유지 관리 가능한 코드를 생성할 수 있으며 바이브 코딩의 코드 품질 및 사용자 정의 한계를 직접적으로 해결할 수 있다.
  • AI 네이티브 도구 및 통합 개발 가속화: 바이브 코딩의 빠른 프로토타이핑 기능을 활용하여 맞춤형 MCP 클라이언트나 특정 시스템과 AI를 연결하는 맞춤형 통합 솔루션을 신속하게 구축하고 반복할 수 있다. 이는 새로운 AI 기반 솔루션의 시장 출시 시간을 단축하고 인프라 개발 자체를 가속화한다.
  • 견고한 AI 에이전트 오케스트레이션 및 자체 확장: MCP의 고급 다중 도구 에이전트 워크플로우 지원과 바이브 코딩의 빠른 반복 기능을 결합, 복잡하고 컨텍스트 인식적인 AI 에이전트를 개발하여 동적으로 확장할 수 있다. AI 에이전트는 필요에 따라 새로운 도구를 즉석에서 ‘바이브 코딩’하고 ‘MCP’를 통해 통합하여 활용함으로써 자율적이고 잠재적으로 자체 개선되는 AI 시스템을 생성할 수 있다.
  • 기술 및 비기술 사용자 연결 (일반인 AI 개발): 바이브 코딩의 접근성(비전문가도 자연어로 개발할 수 있는)과 MCP의 안전하고 거버넌스 된 엔터프라이즈 데이터 및 시스템 노출을 결합하면, 도메인 전문가는 있지만 전통적인 코딩 기술이 없는 개인(일반인 개발자!)도 중요한 기업 데이터를 활용하는 기능적 애플리케이션이나 자동화를 신속하게 생성할 수 있다. 이는 AI기술과 그 혜택을 더 많은 사람들이 누릴 수 있도록 AI 개발을 민주화하고 디지털 전환을 가속한다.
  • MCP 원칙을 통한 바이브 코딩 한계 완화: MCP의 컨텍스트 무결성, 모듈식 유연성, 보안 및 거버넌스와 같은 핵심 원칙을 바이브 코딩 프로세스에 체계적으로 적용함으로써, 코드 품질, 보안 위험 및 AI에 대한 과도한 의존성과 같은 바이브 코딩의 내재된 단점을 해결할 수 있다. 이것은 바이브 코딩을 잠재적으로 위험한 실험적 접근 방식에서 더 신뢰할 수 있고 감사할 수 있으며 기업에 적합한 방법론으로 끌어올릴 수 있다.

결론적으로, MCP는 바이브 코딩이 우수하고 더 신뢰할 수 있는 결과를 생성하기 위해 소비하는 구조화되고 안전한 컨텍스트를 제공하는 자연스럽고 강력한 조합을 만들 수 있다. 이는 향후 소프트웨어 개발 워크플로우가 전체 소프트웨어 개발 수명 주기(SDLC) 전반에 걸쳐 AI 시스템에 포괄적이고 실시간 컨텍스트를 정의, 관리 및 제공하는 것을 점점 더 우선시할 것임을 의미하며, 컨텍스트를 개발에서 코드 자체보다 우선하는 일반인 개발자를 최우선으로 고려할 수 있다.

 

4. Beyond Next

MCP와 바이브 코딩의 결합은 소프트웨어 개발의 새로운 패러다임이다. 이 두 기술의 시너지는 단순한 개발 도구를 넘어서, 비즈니스 프로세스 전반의 디지털 트랜스포메이션(Digital Transformation)을 가능하게 하며, 이러한 강력한 시너지는 조직이 더욱 정교하고 자율적인 AI 에이전트를 구축하고, 제품 개발 주기를 극적으로 가속화하며, 일반인 개발자를 포함한 더 광범위한 다수의 기여자들이 디지털 솔루션 생성에 의미 있게 참여할 수 있도록 역량을 강화할 수 있다.

✔️ 기업 실무자가 체크해야 할 것

  • 조기 도입의 중요성: 기업은 남들보다 빠르게 경쟁력을 확보하기 위해서는 MCP 기반 워크플로우와 바이브 코딩 환경을 조기에 도입해야 할 필요가 있다. 이를 통해 초기에는 통제된 작은 파일럿 프로젝트로 시작하여 학습 및 개선을 도모하면서 점차 그 범위를 넓혀가며 업무에 실제 적용해 본다. 이 모든 것은 강력한 경영진의 의지와 실행력에 달려있다.
  • 내부 시스템 표준화 및 MCP 인프라 투자: 기존 시스템의 MCP 연동을 위한 표준화 작업을 수행하고, 잘 정의되고 접근 가능하며 안전하게 관리되는 컨텍스트 데이터를 위해 강력한 MCP 서버 구축, 데이터 거버넌스 정책 수립, 효율적인 데이터 파이프라인 개발에 투자해야 한다. 이를 위해서는 기존 레거시 시스템에 대한 전반적인 검토, 정리가 필요할 수 있다.
  • AI 활용 역량 강화 및 개발자 역할 재정의: 기업은 소프트웨어 개발자의 역할이 진화할 것임을 인정하고, 기존 개발자에게 AI 생성 코드를 안내, 테스트 및 검증하는 역할로 전환할 수 있도록 포괄적인 교육을 제공해야 한다. 또한 MCP를 활용하여 고급 컨텍스트 관리, AI 에이전트 오케스트레이션 및 안전한 통합을 수행하는 방법 또한 교육이 필요하다. 이는 신기술에 내몰리는 인력이 아닌, 인력을 역량을 강화하여 기업의 핵심인재로 거듭날 수 있는 기회를 제공하는 것이다.
  • 포괄적인 AI 거버넌스 및 보안 프레임워크 구축: MCP 및 바이브 코딩의 잠재적 보안 위험을 고려하여, 모든 AI 생성 코드 및 AI 에이전트 상호 작용에 대한 강력한 보안 프로토콜, 지속적인 감사 메커니즘 및 명확한 거버넌스 정책을 구현하는 것이 중요하다. 이를 위해선 전문화된 인력과 조직이 필요하다.
  • 실험 및 협력적 혁신 문화 조성: ‘바이브 코딩 사고방식’을 수용하여 부서 간 협업, 신속한 반복 및 창의적인 문제 해결을 장려해야 하며, 동시에 이러한 문화가 MCP에 의해 촉진되는 안전하고 컨텍스트가 풍부한 환경에 기반을 두어 무결성을 손상시키지 않고 민첩한 개발을 가능하게 해야 한다. 쉽지 않은 일이며 조직문화와 풍토 면에서 많은 고민이 필요할 수 있다.

AI 에이전트 시대에 소프트웨어를 구상하고 구축하며 배포하는 방식은 근본적으로 재편될 것이고, MCP와 바이브 코딩의 전략적 통합은 인간의 창의성, 전략적 감독 및 도메인 전문 지식이 AI의 탁월한 속도, 컨텍스트 처리 능력 및 자동화와 결합되는 강력하고 고도로 효율적인 하이브리드 모델을 시사한다. 이는 빠르게 진화하는 AI 시대에 확장 가능한 혁신을 달성하고 경쟁 우위를 유지하려는 조직에게 전략적 필수 요소가 될 것이며 기업의 경영진은 많은 관심과 지원을 아끼지 않아야 한다.

소프트웨어 규모 산정 – 기능점수 (프로젝트 성공률 1% 높이기)

소프트웨어 규모 산정: 기능점수

컴퓨터를 기반한 시스템을 구축하면서 가장 비용이 많이 든 요소는 다름이 아니라 소프트웨어이다. 그래서 소프트웨어의 규모를 알아내는 일이 매우 중요하며 그 역사도 매우 깊다. 이러한 소프트웨어 비용은 사람, 기술, 환경 및 이를 둘러싼 정치, 정책이란 여러 변수의 영향을 많이 받는다. 그래서 소프트웨어 비용의 신뢰성을 높이고 그 노력을 추정하기 위해 많은 방법이 있었다. 프로젝트가 끝날 때까지 추정을 미뤄보기도 하고 소프트웨어 공학을 활용하여 활동들을 분해하여 분석하기도 했으며 과거의 경험과 데이터를 바탕으로 추정하고 도구를 사용하기도 했다.
 
특히 개발 프로젝트의 대상인 소프트웨어의 범위를 양적인 크기와 질적인 수준으로 측정하여 규모를 파악함으로써 소요 공수, 투입자원 및 소요 기간을 파악하여 실행할 수 있는 계획을 수립하기 위해 규모를 산정한다. 이를 통해 투입인력 개개인의 생산성을 측정할 수 있으며 원가를 파악하여 비가시적인 소프트웨어 개발에 대한 최소한의 재무적 성과를 구축할 수 있다. 또한 조직의 실효성 있는 경영계획과 정책 수립에 크게 이바지를 할 수 있다.
 
앞선 글에서도 언급했었지만 소프트웨어 규모를 산정하는 방법은 다양하다. 양적 규모를 산정하는 방법에는 LOC(Line Of Code) 방식, Putnam(생명주기 예측) 모델 및 CoCoMo(Constructive Cost Model) 등이 있고 질적 규모를 산정하는 방법에는 기능점수(Function Point), McCabe 회전 복잡도, Halstead 소프트웨어과학 등이 있다. 과거에는 소프트웨어도 단순하고 규모가 크지 않아 양적 규모 산정 방법만으로도 충분했으나 근래에는 소프트웨어의 복잡도도 증가하고 그 규모도 너무나 커져서 질적 규모 산정 방법으로 접근하며 그중에서 Fuction Point를 많이 사용하는 추세이다.
 
 

기능점수방식(Function Point)

Fuction Point는 사용자 관점에서의 소프트웨어 개발 규모를 측정하기 위한 표준 ISO/IEC 14143(FSM: Functional Size Measurement)기법으로서 사용자가 요구하여 받는 기능들을 측정하고 구현 기술과 무관하게 소프트웨어 개발 및 유지보수의 규모를 산정할 수 있다. 여기서 기능점수란 사용자 관점에서의 측정된 소프트웨어 기능의 양을 말하며 소프트웨어 기능은 논리적 의미에 따라 데이터와 트랜잭션으로 크게 나눠 볼 수 있다.
 
기능점수방식에서도 크게 일반적인 기능점수 산정 방법(정통 법)과 평균 복잡도를 적용하는 방법(간이 법)의 두 가지가 있으며 정통 법은 소프트웨어 기능을 도출, 각 기능의 유형별 복잡도를 고려하는 일반적인 방법으로 소프트웨어 개발 설계공정 후에 보통 사용되며, 간이 법은 기능의 복잡도를 판단하기 어려운 경우에 적용하며 계산 절차는 정통법과 동일하나 기능점수를 기능 유형별 평균 복잡도를 적용하여 산출한다. 이는 보통 기획 및 발주단계에서 사용된다.

 

비용과 노력 추정 매트릭스

< 비용과 노력 추정 매트릭스 >

기능점수방식은 기능을 중심으로 하는 소프트웨어와 개발과정에 대한 간접척도를 다루며 프로젝트 완료 후 생산성 평가목적으로 개발되었으나 사전 예측 모델로도 이용되고 있다. 이를 좀 더 살펴보면 생산성은 FP/노력으로 볼 수 있으며 품질은 오류 발생률(오류 수/FP)로 측정할 수 있다. 결함 수를 FP로 나누면 결함 발생률이며 비용효율성(=비용/FP) 및 문서화를 위한 측정도 가능하다.
 
이런 기능점수방식은 프로그래밍 언어와 독립적이어서 환경에 영향을 받지 않는 큰 장점이 있다. 하지만 보다시피 이를 잘 활용하기 위해서 숙련된 기술이 필요하고 주관적인 자료들도 많고 수집도 어려운 점이 있다. 특히 사용자 관점에서 이뤄지다 보니 감춰진 측정항목들이 있으며 사용되고 있는 파일 수를 정확히 파악하기가 어렵다.
 
아래는 기능점수에서 사용하는 5가지 측정 항목이다.
 

기능점수 5가지 측정 항목

 
EI(External Input)는 외부 입력측정(사용자 입력 개수), EO(External Output)는 외부 출력측정(사용자 출력 개수), EQ(External inQuery)는 외부 조회측정(사용자 질의 개수)이다. ILF(Internal Logical File)은 내부파일 개수, EIF(External Interface File)는 외부 인터페이스 개수이다.
 




계산 방법

🚩 단계1 : FP 테이블에 따른 기능 수 계산
기능유형                      Count  |  단순  |  보통  |  복잡  |  기능수(FC)
외부 입력:                       [ ]*        3         4         6         = [  ]
외부 출력:                       [ ]*        4         5         7         = [  ]
외부 조회:                       [ ]*        3         4         6         = [  ]
내부 논리파일:                 [ ]*        7        10       15         = [  ]
외부 인터페이스 파일:       [ ]*        5          7       10         = [  ]
 
🚩 단계2 : 복잡도 조정값 계산
14개 기술적 복잡도 요소에 영향도(0 ~ 5의 정수 표시)를 평가하여 합산하여 계산한다. 총영향도(0~70)는 항목(14개)에 영향도(0~5)를 곱하며 기술적 복잡도(TCF)는 0.65 +0.01 * 총영향도로 나타낼 수 있다. 여기서 14개 요소에는 통신, 분산처리, 시스템성능, 사용 빈도, 트랜잭션 비율, 온라인 요구, 온라인복잡도, 파일갱신, 재사용성, 처리 복잡성, 유지보수성, 회복성, 이식성, 분산성이 있다.
 
🚩 단계3 : FP 계산
기능점수(FP)를 계산하며 FC (기능 수)에 TCF (기술적 복잡도)를 곱한다.
 
🚩 단계4 : 경험 데이터 이용 프로젝트 비용과 개발 노력 추정
전체적인 프로젝트 비용은 FP에 FP 당 비용(경험치)을 곱하며, 개발 노력은 FP를 생산성(경험치)으로 나눠 측정한다.
 
 
 
 
※ 직접 해봐야 안다.
쉽지는 않다. 과거의 유사 사례 경험, 양식들이 있다면 우선은 먼저 자료를 구해서 진행하고 있는 프로젝트에 적용해 보길 바란다. 쉬운 방식으로 몇 번 하다 보면 얼추 감이 온다. 그러면서 다른 산정 방법도 같이 하여 서로 값을 비교해보는 것도 좋다. 자주 해보고 나만의 경험을 쌓고 데이터를 쌓아가면서 공부를 해봐야 한다.

테일러링 (프로젝트 성공률 1% 높이기)

테일러링(Tailoring) 이란?

소프트웨어 개발은 소프트웨어를 생성하고 유지하는 과정으로 다양한 방법과 기술이 사용되며 프로젝트의 특성에 따라 최적화된 방법과 기술을 선택하는 것이 매우 중요하다. Tailoring은 특정 프로젝트의 요구 사항에 대하여 소프트웨어 개발 프로세스나 방법론을 적절하게 조정하고 필요 활동을 가감하는 것이다. 다시 말해, 소프트웨어 개발 프로세스는 규모, 복잡성, 요구사항, 조직 문화 및 프로세스 등 여러 제약 조건에 따라 달라지는데 이러한 요소를 고려하여 프로젝트에 가장 적합한 프로세스를 선택, 조정하는 것을 의미한다.
 
이런 조정의 조치는 소프트웨어 개발 프로젝트의 성공에 핵심적인 요소이다. 모든 것이 목표를 지향하고 나아가지만 100% 수행될 수는 없다. 그래서 프로젝트 진행 중에 발생하는 각종 위험을 줄이고, 품질을 향상하며, 시간과 비용을 단축할 수 있는 방법으로 우리는 Tailoring을 한다. 그래서 Tailoring은 프로젝트 초기 단계에서 고려하고 실시하여야 한다. 프로젝트가 시작되면 진행 중 반드시 새로운 요구사항이 나올 수 때문에 Tailoring을 통해 이러한 요구사항을 미리 반영하는 것이다.
 
 

Tailoring 종류

Tailoring에는 몇 가지 종류가 있으며 이를 통해 부분별로 최적화를 진행할 수 있다. 이는 프로젝트의 특성, 목적, 예산, 일정, 규모, 복잡성, 기술적/사업적 요구사항, 개발역량, 도구, 조직문화 및 각종 제약조건에 따라 고려되고 선택될 수 있다.
 
🚩프로세스 Tailoring
: 소프트웨어 개발 프로세스는 소프트웨어를 개발하기 위한 일련의 단계와 활동으로 구성되어 있는데 이 특성에 맞게 소프트웨어 개발 프로세스를 조정하여 프로젝트 규모에 따라 단계와 활동을 강화 또는 제거하여 효율적인 운영을 하는 것이다.
 
🚩 기술 Tailoring
: 프로젝트 기술 또한 프로젝트의 특성에 맞춘다. 무조건 고급기술을 지향하는 것이 아니라 요구 성능에 적절한 기술을 도입하여 반영하고 운영하는 것이다. 이럼으로써 불요한 기술 비용 등을 줄일 수 있다.
 
🚩 사람 Tailoring
: 소프트웨어 개발 프로젝트의 인력은 프로젝트의 특성에 맞게 조정해야 한다. 개발 프로젝트 난도가 높다면 고경력의 인력을 보다 많이 투입할 수 있는 것이다.
 
 

Tailoring 절차

Tailoring은 개발 프로젝트의 특성을 고려하여 프로젝트의 목표, 범위, 일정, 예산, 인력 및 기술에 따라 어떤 방법과 기술이 필요한지를 판단해야 한다. 이를 위해 다음의 단계를 거친다.
 
✅ 요구 사항 분석

: 프로젝트의 목표와 요구 사항을 분석하고 이해한다. 이를 위해 이해당사자들과의 의사소통, 현장 조사, 문서 검토 등을 수행하여 요구 사항을 명확히 이해하고 프로젝트의 고유한 요소를 파악한다.

✅ 방법론 선택
: 요구 사항 분석을 토대로 조정이 필요한 영역을 파악하고 이에 따른 방법론을 선택한다. 이는 기준이 되는 표준 방법론에서 일부 요소를 선택하거나 다른 방법론을 조합할 수도 있다. 

✅ 프로세스 조정

: 방법론을 조직과 프로젝트에 맞게 조정한다. 이 과정에는 수명주기 단계 추가 또는 제거, 프로세스 세부 조정, 가이드라인과 절차 수정 등이 포함될 수 있다.

✅ 도구와 기술 선택

: 조정된 방법론에 맞는 도구와 기술을 선택한다. 프로젝트에 필요한 특정 기능을 구현하기 위해 특정 개발 도구나 프레임워크를 도입할 수도 있다. 어느 하나를 끝까지 고수할 필요는 없다.

✅ 팀 구성원 역할 및 책임 조정

: 조정된 방법론에 따라 팀 구성원의 역할과 책임을 조정한다. 팀 구성원은 방법론에 맞게 업무를 수행해야 하고 원활한 의사소통과 협업을 진행해야 한다. 팀원들의 역량과 역할에 따라 재조정 또는 새로운 역할을 부여할 수 있다.

✅ 프로젝트 관리 및 모니터링

: Tailoring 된 방법론으로 프로젝트를 관리, 모니터링한다. 이는 일정 관리, 리스크 관리, 품질 관리, 의사소통 관리 등을 포함으로써 프로젝트 진척 상황을 주기적으로 검토하고 필요한 조정을 수행하여 프로젝트 목표 달성을 보장한다.

✅ 지속적 개선

: Tailoring은 프로젝트 진행 중에도 지속해서 개선되어야 한다. 이를 통해 방법론의 효과성과 프로세스의 개선점을 도출하고 반영한다. 
 




 

Tailoring 효과

소프트웨어 개발은 정말 복잡한 과정이다. 이러한 개발 프로젝트를 성공적으로 수행하려면 다양한 요소를 고려해야 하는데 Tailoring이야말로 최상의 결과가 나오도록 모든 것을 잘 매만져 주는 일이다. 이를 통해 프로젝트는 프로젝트의 특성에 맞게 최적화될 수 있고 그 효과는 여러 가지로 나타난다.
 
✔️ 요구 사항 충족
: 프로젝트 특정 요구사항을 위해 방법론이 조정되면 큰 틀에서 매우 효과적인 방법론의 채택을 통해 프로젝트의 속도를 향상한다. 이때 방법론을 처음부터 끝까지 고집할 필요가 없으며 필요 부분에 대해서만 다른 방법론을 활용할 수도 있다.
✔️ 조직 맞춤화

: 고유한 사업적 요구 사항과 제약 조건을 가진 조직은 Tailoring으로 인하여 조직 내 체계를 활성화하고 조직에 맞는 색깔을 찾아 입힐 수 있다. 이에 따라 살아 움직이는 조직으로 보다 유연한 관리가 가능하다.

✔️ 자원 최적화

: 프로젝트 규모와 복잡성에 따라 초기 계획을 지속 관리하고 필요한 자원과 비용을 효과적으로 조절할 수 있다. 즉, 불필요한 자원의 집행을 사전에 확인, 관리할 수 있는 역량을 갖추어 비용과 시간을 절감할 수 있다.

✔️ 프로젝트 성공

: 프로젝트를 성공시킬 수 있는 확률이 높다. 방법론의 수정으로 조직과 프로젝트에 최적화되고 보다 더 적절한 접근 방식에 따라 위험을 완화하고 품질을 향상할 수 있다. 이는 궁극적으로 고객 만족도를 높인다.
 
 
 
※ Tailoring 한계
어떻게 보면 프로젝트 시작과 함께해야 할 Tailoring. 그만큼 중요하다는 것을 알지만 이를 실제로 수행하는 프로젝트나 조직은 매우 드물다. 물론 하기는 하지만 공식적인 형태를 갖추고 제대로 하는 곳이 별로 없단 이야기다. 꼭 이렇게 부르지 않더라도 모든 단계, 조직에서 Tailoring을 하는데 이것이 왜 힘들까? 일단 시간이 없다. 모두 바쁘다. 프로젝트가 본격 궤도에 오르면 앞만 보고 가기에도 힘겹다. 또한 사람이 없다. Tailoring을 제대로 하려면 전문가가 필요하다. 프로젝트와 방법론 전반을 꿰찬 인력은 갈수록 부족하다. 그러다 보니 결국엔 돈이다. 그런데 이런 예산을 기획 단계에서 고려하여 잡아주는 프로젝트가 과연 얼마나 되는가? 결국 핑계? 핑계여서 하지 못한다 한들 해야한다. 누군가는..

프로그래밍1 (소프트웨어 공학)

프로그래밍 – 구현

설계작업들이 끝나면 시작되는 소프트웨어 프로그래밍은 요구사항에 대한 실질적인 구현행위이다. 특히 분리하여 구현할 수 있는 작은 단위로 나눠 작업을 한다. 프로그래밍의 수행이 상세 설계나 사용자 지침에 기술된 내용과 일치되도록 작업하여야 한다. 이 작업에서 가장 중요한 것은 표준을 정하고 준수하고 이에 따라 정확하게 작성하는 것이다. 소프트웨어의 품질은 결국 이를 얼마나 잘 수행하여 원시 코드에 반영하느냐이다. 따라서 프로그래밍에서는 소프트웨어의 기능구현이 급급한 것이 아니라 요구되는 품질에 얼마나 부합하도록 작업하는가에 대한 관심과 끊임없는 노력이 매우 중요하다. 

※ 코딩과 프로그래밍?
이 용어는 모두 컴퓨터와 상호 작용하고 컴퓨터 시스템을 생성하고 유지 관리하는 데 중요한 기술로 종종 같은 의미로 사용되지만, 프로그래밍 과정 중 코드를 작성하는 구체적인 단계를 가리키며, 프로그래밍은 문제 해결을 위한 전체적인 과정을 의미하기에 사실은 서로 다르다.

  • 코딩(coding): 프로그래밍의 하위 세트 중 하나로 구체적으로 언어의 문법을 따라 컴퓨터가 이해할 수 있는 명령어를 작성(원시 코드)하는 작업으로, 프로그램 로직을 작성하고 알고리즘을 구현하며 문제를 해결하기 위한 코드를 작성하는 활동
  • 프로그래밍(programming): 문제 해결을 위해 컴퓨터에 명령을 전달하는 전체적인 과정으로 문제를 이해, 정의하고 요구사항을 분석하며 그에 따라 적절한 알고리즘과 데이터 구조를 선택한 후 코드를 작성하는 단계와 함께 디버깅, 테스트, 최적화 등의 소프트웨어 개발 과정을 포괄하는 개념으로 컴퓨터 시스템을 생성하고 유지관리하는 프로세스



프로그래밍 원리

앞서 용어 정의와 같이 코딩은 프로그래밍 작업이다. 이러한 구현단계의 목표는 설계 명세에 나타난 대로 사용자 요구를 만족할 수 있도록 프로그래밍을 하는 것이다. 이렇게 하기 위해서는 코딩 단계에서는 전 단계의 문서들을 잘 참조하여야 한다. 특히 무엇보다도 오류가 적은 품질 좋은 프로그램을 작성하는데 그 목표가 있다. 신속성도 중요하지만 견고한 코드를 만들어내는 것에는 많은 연습과 경험이 필요하다. 이를 위하여 수많은 원리와 가이드를 만들고 잘 참고해야 한다.

일반적인 객체지향 코딩에는 다음과 같은 단계가 있다.

  • 원시 코드 스타일의 코딩표준 작성
  • 아키텍처 설계 결과 프레임워크 패키지와 응용 패키지 결정
  • 패키지 내 각 클래스에 대해 요구사항과 상세설계를 반영한 메소드 코딩
  • 클래스 구현 후 인스펙션 실시
  • 클래스 단위 테스트 진행
  • 클래스/패키지를 배포, 통합

이러한 작업을 진행하면서 오류는 프로그래머가 가장 신경 써야 할 부분 중 하나다. 개발과정에서는 특히 많은 시간이 오류를 찾고 해결하는 데 쓰이는데 일정 부분 이상은 흔히 발견되는 오류로 이를 알고 접근한다면 많은 부분의 비용을 절감할 수 있다. 아래는 여러 오류 중 중요한 몇 가지의 예이다.

  • 메모리 누수: 이는 메모리가 풀리지 않고 계속 할당하는 현상으로 보통 가비지 컬렉션이 자동으로 되지 않은 언어에서 이러한 오류가 자주 발생한다. 메모리 누수는 규모가 작은 프로그램에서는 영향이 적지만 대규모 환경에서는 시스템에 매우 치명적인 영향을 줄 수 있으므로 반드시 잡아야 한다.
  • 중복된 해제 선언: 프로그램 내에서는 자원할당 후 사용 후 해제해야 한다. 그런데 해제된 자원을 또다시 해제하는 경우도 매우 심각할 수 있다. 만약 두 개의 해제문장 사이에 메모리 할당 호출이 있다면 이런 오류의 영향은 예측할 수 없다.
  • NULL: null을 포인트하고 있는 곳의 내용에 접근하려고 하면 오류가 난다. 이는 시스템을 다운시키기에 충분하다. 그런데 찾기도 어려운 것이 이것이다.
  • 배열 인덱스 오류: 배열 인덱스의 한도를 벗어나면 예외 오류가 발생한다. 그러므로 인덱스가 음수 또는 한도를 벗어나지 않는지 항시 확인하여야 한다.
  • 수식 예외: 0으로 나눈다거나 변동 소수점 예외 오류 등이다. 
  • 사용자 정의 자료형: 오버플로우나 언더플로우가 특히 많다. 
  • 버퍼 오류: 보안결함에서 많이 발견되는 유형으로 해커들의 잠입 루트가 되기도 한다. 
  • 동기화: 공통된 자원에 접근하는 다수의 스레드가 있는 병렬 프로그램에서 흔하게 발견된다. 이 또한 쉽게 발견되기가 어려운데 시스템에는 막대한 지장을 줄 수 있다. 흔히 deadlock이 여기에 속한다.

구조적 프로그래밍, 이를 위해서 많이 사용하는 제어구조가 있는데 순차, 선택, 반복이다. 이 또한 제대로 된 흐름제어 기준을 정해놔야 한다. 무조건적인 제어의 흐름을 막고 알고리즘을 명확하게 구현할 수 있는 가이드를 제시하고 공유한다. 물론 근래의 프로그래밍 언어들은 이를 고려하여 여러 명령어나 제약을 두고 있으며 필요하다면 비구조적 문형으로 개발을 할 수도 있다.

또한 모든 프로그램에는 항상 도메인에 관한 정보를 다루기 때문에 자료구조가 항시 존재한다. 그래서 특정 정보에 대해서는 정해진 오퍼레이션만 적용된다. 즉 문제 도메인에 있는 아주 작은 정보가 제한된 방법으로만 사용된다는 것이다. 이를 앞서 다뤄본 정보은닉의 원리 적용이다. 정보은닉이란 모듈 사이의 결합을 줄이고 시스템의 유지보수를 쉽게 만드는 장점을 가지고 있고 데이터를 관리하려는 관점과 데이터를 사용하는 관점을 분리할 수 있는 것이다.



코딩 스타일

프로그래밍 스타일이다. 같은 작업을 위하여 여러 사람이 작성한 프로그램들은 문장의 패턴이나 그 구성 등 여러 면에서 다른 스타일을 보인다. 각자의 개성이다. 하지만 이를 방치할 경우 프로젝트는 원하는 목표를 달성하기 어렵다. 그래서 가르치고 학습할 수 있는 공통된 스타일을 만들어야 한다. 물론 여기에서도 기준을 구하기 어려울 수도 있지만 가장 근본은 간결하고 읽기 쉬워야 한다는 것이다. 이를 기준 삼아 코딩 스타일을 만든다.

  • 명명 규칙 예
    • 패키지: 타 사용자들을 위해 패키지 이름 앞에 도메인명을 붙인다. 이를 통해 패키지의 용도와 목적을 잘 나타낼 수 있다.
    • 타입: 클래스(명사)와 인터페이스(명사, 형용사) 등의 명칭 첫 글자를 대문자로 한다. 이는 일반 변수와 구별할 수 있다.
    • 메소드: 타입과 달리 첫 글자를 소문자(동사)로 하고 연속되는 단어의 첫 글자는 대문자로 한다. 이는 메소드 호출과 생성자 호출과 구별할 수 있게 해준다.
    • 변수: 메소드와 같은 형식이다.
    • 상수: 보통 대문자로 구성하며 단어 사이는 밑줄로 연결한다.
  • 포인터와 레퍼런스: 포인터를 매개변수로 사용하지 않고 레퍼런스 타입으로 한다.
  • 자료형: 오브젝트 타임을 돌려보내는 클래스는 특정 타입의 객체를 배출하도록 캐스트 한다.
  • 문장과 수식: 반복 문장이나 수식은 메소드나 클래스로 패키지화하여 사용한다.
  • 오류처리: 오류 데이터 타입 제한, 입력 처리 전 데이터 소스와 인터페이스 하여 사전 확인 등의 방법이 필요하다.
  • 들여쓰기: 코드 블록의 계층 구조를 명확하게 표현할 수 있게 공백 문자나 탭을 사용한다.
  • 주석: 코드 설명을 부가적으로 추가한다. 양의 문제보다는 내용을 정확히 전달하는 것이 중요하다.
  • 코드 문서화: 다른 사람들이 정확하게 사용할 수 있도록 주석을 명확히 하고 문서화도 병행한다.
  • 포맷 도구 사용: 개발 환경 편집기에 있는 기능으로 스타일가이드를 바탕으로 세팅하여 사용할 수 있다. 이를 통해 일관된 스타일 유지가 가능하다.

객체지향 분석설계2 (소프트웨어 공학)



UML

무엇이든지 복잡한 생각이나 아이디어를 간결하고 정확하게 표현하려면 여러 방법이 있지만 이를 통해서 의사소통의 오류를 줄이는 것은 소프트웨어 개발 프로젝트에선 필수사항이다. 정확한 의사소통은 먼저 표현하는 의미를 잘 정의해야 하고 대상을 표현하는 데 적합하고 모든 이해당사자가 이해하기 쉬워야 한다. 그래서 표준이나 규격이 필요한 것이고 이것이 객체지향에서는 UML(Unified Modeling Language)을 사용하는 것이다.

UML은 OMT(Object Modeling Technique)와 Booch, OOSE(Obect Oriented Software Engineering)의 통합으로 만들어진 표현 방법으로 객체지향 분석설계기법으로 매우 유용하고 시스템 개발에선 크게 기능적 모형, 객체 모형 및 동적 모형으로 구성된다. 이 중 중요한 다이어그램이 5가지 있는데 Use Case, Class, Sequence, State, Activity가 그것이다.

  • Use Case Diagram
    : 시스템의 기능적인 측면을 모델링하는 데 사용되고 주로 사용자와 시스템 간의 상호작용을 보여준다. 액터(Actor)는 시스템과 상호작용하는 주체(사용자 또는 외부 시스템)를 나타내며 유스케이스(Use Case)는 시스템이 수행하는 기능을 나타낸다.
  • Class Diagram
    : 시스템의 정적인 구조를 모델링하는 데 사용되며 클래스, 인터페이스, 연관 관계, 상속 관계 등을 시각적으로 표현한다. 클래스 다이어그램은 소프트웨어의 구조를 이해하고 객체 간의 관계를 잘 파악할 수 있다.
  • Sequence Diagram
    : 시스템의 동적인 동작을 시간의 흐름에 따라 나타내며 객체 간의 메시지 교환을 보여주고 객체 간의 상호작용과 시간 순서를 시각화하여 효과적으로 커뮤니케이션 흐름을 이해할 수 있게 한다.
  • State Diagram
    : 객체의 생명주기와 상태 변화를 모델링하는 데 사용되며 주로 객체의 상태가 어떻게 변화하고 이벤트에 응답하는지를 시각적으로 보여준다. 상태 다이어그램은 복잡한 객체의 동작을 이해하는 데 필요하다.
  • Activity Diagram
    : 비즈니스 프로세스나 시스템의 작업 흐름을 시각화하는 데 사용된다. 활동은 작업 단계를 나타내며 화살표로 연결된 동작의 흐름을 보여주고 제어 흐름, 의사 결정, 병렬 처리 등을 표현하여 프로세스를 이해하고 분석하는 데 활용된다.

 

설계/구현 매핑

객체지향 모델링에는 크게 네 가지 관계, 연관, 전체/부분, 상속, 사용 관계가 그것인데 이들의 각각의 관계는 클래스 또는 객체가 관계를 맺고 있는 특별한 유형을 의미한다. 이에 각각 살펴보면 다음과 같다.

  • 연관관계 (Association)
    : 클래스 간의 관계이며 어떤 클래스의 객체가 다른 클래스의 객체와 상호작용하는 것을 나타낸다. 연관은 일반적으로 양방향 또는 단방향으로 설정될 수 있고 연관에는 다중성(multiplicity)과 역할(role)이 포함될 수 있다. 다중성은 연관에 참여하는 객체의 수를 나타내며, 역할은 해당 연관에서 객체가 가지는 역할을 의미한다.
  • 전체/부분관계 (Composition/Aggregation)
    : 한 객체가 다른 객체의 부분이 되는 관계로 Composition은 전체와 부분 사이에 강한 소유관계가 있는 경우를 의미하며 전체 객체가 파괴되면 부분 객체도 함께 파괴된다. Aggregation은 더 느슨한 관계로 전체 객체와 부분 객체는 독립적으로 존재할 수 있다. 전체/부분 관계는 다이어그램 상에서 다이아몬드 형태의 다이어그램 요소로 표현한다.
  • 상속 관계 (Inheritance)
    : 상속은 클래스 간의 계층적인 관계를 나타내며 한 클래스가 다른 클래스로부터 속성과 동작을 물려받는 것을 의미한다. 부모 클래스(상위 클래스 또는 기본 클래스)의 특성과 동작을 자식 클래스(하위 클래스 또는 파생 클래스)가 재사용할 수 있도록 하고 이를 통해 코드 재사용성과 확장성을 증가시킬 수 있다.
  • 사용 관계 (Dependency)
    : 한 클래스가 다른 클래스의 기능을 사용하는 관계로서 이 관계에서는 클래스 간에 직접적인 연결이 없으며 주로 메소드의 매개변수나 반환 값 등을 통해 나타난다. 클래스가 다른 클래스의 인터페이스를 사용하여 기능을 구현하는 경우 사용 관계가 형성된다.



시스템/객체 설계

객체지향 설계는 소프트웨어 시스템을 개발하기 위한 계획과 구조를 만드는 과정으로 시스템 설계와 객체 설계는 객체지향 개발의 두 단계로서 각각 전체적인 아키텍처와 개별 객체의 세부 사항을 다룬다. 이 둘은 서로 밀접하게 연관되어 있으며 시스템 설계 단계에서 결정된 아키텍처와 모듈화는 객체 설계 단계에서 각 객체의 역할과 협력을 결정하는 데 사용된다. 따라서 객체지향 설계는 시스템의 기능, 구조, 동작을 종합적으로 고려하여 효율적이고 확장 가능한 소프트웨어 시스템을 개발하는 데 필요하다.

  • 시스템 설계
    : 소프트웨어 시스템 전체의 아키텍처와 구조를 정의하는 단계로 다양한 컴포넌트 간의 관계, 모듈화, 시스템의 구조적인 레이어 등을 결정한다.

    • 시스템 아키텍처 설계: 전체 시스템 아키텍처, 레이어 구조, 서브 시스템 등을 정의하며 시스템의 큰 틀을 잡아내고 시스템의 기능적 요구사항을 충족시키기 위한 아키텍처를 선택한다.
    • 모듈 설계: 시스템을 여러 개별 모듈로 분리하고 각 모듈의 역할과 책임을 정의한다. 이 모듈 간의 인터페이스와 상호작용 방법을 결정하여 시스템 전체의 유기적인 통합을 보장한다.
    • 데이터베이스 설계: 시스템에서 사용되는 데이터의 구조와 관계를 정의하며 데이터의 저장, 검색, 관리 등을 위한 데이터베이스 구조와 스키마를 설계한다.
  • 객체 설계
    : 객체 설계는 시스템 설계의 결과물을 기반으로 각각의 객체와 클래스의 구조, 속성, 메소드 등을 정의하는 단계로서 시스템 설계에서 정의한 모듈을 실제로 구현 가능한 형태로 변환한다.

    • 클래스 정의: 클래스의 속성과 메소드를 정의하고 클래스의 책임과 역할을 명확히 한다. 클래스의 인터페이스와 구현을 결정하여 다른 클래스와의 협력 관계를 구성한다.
    • 객체 간의 관계: 연관, 전체 부분, 상속, 사용 관계 등을 통해 객체 간의 관계를 설정하며 이를 통해 객체들의 협력과 상호작용을 정의한다.
    • 동적 동작 정의: 시퀀스 다이어그램과 같은 다이어그램을 사용하여 객체 간의 상호작용을 시각화하고 메소드 호출 순서와 결과를 정의한다.

 

디자인 패턴

객체지향 설계작업은 방법론이 있지만 쉬운 작업은 아니다. 이를 위해선 많은 경험과 인사이트가 필요하다. 이에 객체 설계의 경험을 토대로 한 디자인패턴 개념이 등장한다. 디자인패턴은 프로그램 개발에 자주 등장하는 문제를 기술하고 같은 작업을 반복하여 설계하지 않고 여러 번 반복하여 사용할 수 있는 문제에 대한 솔루션을 기술한 것이다. 다만 패턴에서 기술된 솔루션이 특정한 구현을 나타낸 것은 아니며 여러 상황에서 적용될 수 있는 템플릿 성격이라고 보는 것이 맞다. 그래서 문제에 대한 설계를 추상적으로 표현하여 문제를 해결하려는 요소들을 일반화하고 잘 정리한 것이다.

이러한 디자인패턴은 다음과 같은 요소로 구성된다.

  • 패턴 이름/구분: 패턴을 부를 때 사용하는 이름과 패턴 유형
  • 문제/배경: 패턴이 사용되는 분야, 배경 및 해결하려는 문제
  • 솔루션: 패턴을 이루는 요소들, 관계, 협동 과정
  • 사례: 적용 사례
  • 결과: 패턴사용 시 얻게 되는 이점이나 영향
  • 샘플 코드: 패턴이 적용된 원시 코드

패턴을 분류하는 기준은 여러 가지나 보통 23개의 세 가지 유형을 가진 Gamma 분류체계가 일반적인데 아래 간략히 소개한다.

  • 생성 패턴: 객체의 생성 과정을 추상화하고 객체 생성과 조합을 통해 시스템을 유연하고 확장 가능하게 만드는 패턴들이다.
    • Singleton 패턴: 클래스의 인스턴스가 하나만 생성되도록 보장
    • Factory Method 패턴: 객체 생성을 서브 클래스로 분리하여 확장성을 갖춤
    • Abstract Factory 패턴: 관련된 객체들의 팩토리들을 추상화하여 함께 사용
    • Builder 패턴: 복잡한 객체의 생성 과정을 분리하여 객체 생성을 간단하게 구성
    • Prototype 패턴: 객체를 복사하여 새로운 객체를 생성하는 사용
  • 구조 패턴: 클래스나 객체를 조합하여 더 큰 구조를 만들거나, 인터페이스를 결합하여 새로운 기능을 제공하는 패턴들이다. 
    • Adapter 패턴: 서로 호환되지 않는 인터페이스를 함께 동작하도록 변환
    • Bridge 패턴: 추상화와 구현을 분리하여 두 개의 독립적인 클래스 계층 구성
    • Composite 패턴: 개별 객체와 복합 객체를 동일한 방식으로 다루도록 정리
    • Decorator 패턴: 객체에 추가적인 기능을 동적으로 추가
    • Facade 패턴: 복잡한 하위 시스템을 단순화된 인터페이스로 노출
  • 행동 패턴: 객체 간의 상호작용과 책임 분배를 중심으로 다루는 패턴들이다. 
    • Strategy 패턴: 알고리즘을 정의하고 각각을 캡슐화하여 교환 가능 제공
    • Observer 패턴: 한 객체의 상태 변경이 다른 객체에 통지
    • Command 패턴: 요청을 객체의 형태로 캡슐화하여 나중에 실행하거나 취소 가능
    • Chain of Responsibility 패턴: 요청을 처리하는 객체들의 연결을 만들어 책임 위임
    • State 패턴: 객체의 상태에 따라 행동을 변경 가능



객체지향 분석설계1 (소프트웨어 공학)

소프트웨어 개발에서 객체지향 프로그램은 독립 객체들의 묶음이다. 따라 분석과 설계 단계에도 프로그램 모듈 단위인 객체의 정적인 구조와 동적인 변화를 미리 고려해야 한다. 분석 단계에서는 사용자 관점에서 여러 사용 사례를 찾아보고 클래스들의 정적인 관계와 객체들의 인터랙션을 찾아낸다. 설계 단계에선 클래스들의 묶음으로 시스템 구조를 정의하고 클래스 내부를 설계한다. 이러한 분석과 설계과정은 순차적 과정이 아니다. 이는 반복과 점증적 개발 프로세스를 사용하고 있으며 이를 통해 반복적 사이클을 거치면서 점차 확장되고 완성되어 가는 것이다. 

객체지향 분석과 설계과정은 누구나 공통으로 사용하는 프로세스는 없다. 물론 여러 가지 제안 프로세스들이 있으나 모두 상이하다. 이에 모델링은 매우 중요하게 대두된다. 모델은 프로젝트에 참여하는 모든 사람이 목표로 하는 소프트웨어를 잘 이해할 수 있게 하며 이를 사용함으로써 시간과 비용을 절약할 수 있다. 객체지향 분석과 설계에서는 보통 3가지 모델을 사용한다. 이는 기능 모델(Use case Diagram), 객체모델(Class Diagram), 동적모델(State Diagram/Sequence Diagram)이 그것이다.

 





 

Use Case

객체지향을 통해 시스템 개발 시 가장 먼저 할 일은 요구사항을 추출하는 것으로 여기에 Use Case가 사용된다. Use Case는 시스템이 수행할 것으로 기대되는 기능을 말하는데 이는 사용자 또는 외부 시스템이나 기타 요소들이 시스템과 상호작용하는 다이얼로그를 모델링한 것이다. 모든 Use Case는 외부 엔티티들이 시스템과 어떻게 상호작용하는지 가능한 시나리오를 나타내는 것으로 이를 모으면 전체 시스템의 완전한 모습을 보여주는 것이다. 그래서 Use Case는 사용자나 시스템 설계자, 테스터 및 개발자 간 의사소통에 매우 유용하다.

이러한 Use Case는 문제 정의에서 사용사례로 구성된 시스템 명세로 매핑하는 작업이다. Use Case를 작성하고 관계를 찾는 것은 시스템의 요구사항을 명확하게 정의하고 팀 간 의사소통을 원활하게 하며 개발 과정을 체계화하는 것으로 이를 통해 시스템의 기능을 완전하게 이해하고 효과적으로 구현할 수 있다. 이에 대한 작업 과정은 다음과 같다.

  • 액터(Actor) 식별
    • 액터는 시스템과 상호작용하는 외부 역할이나 개체로서 이해관계자, 사용자, 시스템 등이 액터가 될 수 있음
    • 액터를 식별하는 것은 해당 시스템이 상호작용할 주체와 대상을 이해하는 것
  • 시나리오(Scenario) 식별
    • 시나리오는 특정 액터와 시스템 간의 상호작용 과정을 설명하며 시스템의 특정 기능 또는 작업에 대한 흐름 표현
    • 액터마다 여러 시나리오가 있을 수 있음
  • Use Case 작성
    • Use Case는 특정한 기능 또는 작업에 대한 상세한 설명을 담은 문서로 각 Use Case에는 제목, 목적, 참여자(액터), 사전 조건, 후속 조건, 흐름(시나리오), 대안 흐름 등의 정보 포함
    • Use Case를 작성할 때는 해당 기능을 어떻게 사용자가 사용할지를 중심으로 작성
  • Use Case 간 관계 찾기
    • Use Case 간의 관계를 찾는 것은 시스템의 기능적인 흐름을 이해하고 조직화 도움
    • 주요한 두 가지 관계: 일반화 관계(Generalization)와 포함 관계(Inclusion)
      • 일반화 관계: 보다 일반적인 Use Case와 그에 따르는 구체적인 Use Case 간의 상속 관계
      • 포함 관계: 한 Use Case가 다른 Use Case의 일부 기능을 포함하는 관계

 






 

객체 모델링/동적 모델링

Use case를 작성하고 도메인 분석이 어느 정도 마무리되고 나면 객체를 찾고 관계를 정의하는 작업을 시작하게 된다. 이를 객체 모델링이라 부르며, 클래스를 발견하고 난 후 클래스들의 상호작용이나 클래스의 상태 변화 등 시스템 내부의 동작을 구축하는 것을 동적 모델링이라 부르며 UML에서는 Sequence diagram, State diagram, Activity diagram으로 작업한다. 이들은 시스템의 구조와 행동을 모두 고려하여 전체적인 시스템 설계를 돕는 역할을 한다.

  • 객체 모델링 (Object modeling)
    • 객체 모델링은 시스템의 정적인 측면, 즉 시스템 내 객체들의 구조와 관계에 중점
    • 주로 클래스 다이어그램(Class Diagram)과 객체 다이어그램(Object Diagram) 사용
    • 클래스 다이어그램은 시스템 내 클래스(객체의 템플릿)들과 그들 간의 관계를 보여주며 클래스의 속성과 메소드 포함
    • 객체 다이어그램은 특정 시점에서 객체들의 인스턴스와 그들 간의 관계 표현
    • 작업절차
      • 엔티티 클래스 찾기: 시스템의 주요 데이터를 나타내는 클래스로 데이터베이스의 테이블과 유사하며 시스템 내의 중요한 개념이나 사물을 표현
      • 경계 클래스 찾기: 시스템과 외부 환경 간의 상호작용을 처리하는 클래스로 사용자 인터페이스나 외부 시스템과의 통신 담당
      • 제어 클래스 찾기: 시스템의 비즈니스 로직을 처리하고 조정하는 클래스로 엔티티 클래스와 경계 클래스 간의 상호작용 관리
      • 연관관계 찾기: 클래스 간의 상호작용과 관계를 나타내며 엔티티 클래스 사이에 형성되고 방향, 다중성, 역할 등 포함
      • 속성찾기: 클래스나 객체가 가지는 특징이나 데이터를 나타내며 엔티티 클래스의 상태를 설명하는 정보로 사용
  • 동적 모델링 (Dynamic modeling)
    • 동적 모델링은 시스템의 행위나 상호작용을 중심으로 설계
    • 주로 시퀀스 다이어그램(Sequence Diagram)과 상태 다이어그램(State Diagram) 사용
    • 시퀀스 다이어그램은 객체 간의 상호작용 순서를 보여주며 메시지의 흐름을 시각적으로 표현
    • 상태 다이어그램은 객체의 생명주기와 상태 변화를 표현하여 객체의 동적인 행위를 이해하게 지원
    • 작업절차
      • Sequence diagram
        • 객체 간의 상호작용을 시간 순서에 따라 시각적으로 표현
        • 객체 간에 주고받는 메시지와 메시지의 순서를 보여주어 시스템 내부의 상호작용을 이해
        • 시스템의 시간적 흐름을 잘 보여주기 때문에 사용자 스토리나 시나리오를 분석하거나 설계 시 유용
      • State diagram
        • 객체의 생명주기와 상태 변화를 표현
        • 객체가 어떤 상태에서 다른 상태로 전이되는지와 전이가 어떤 조건에서 일어나는지 표현
        • 객체의 행위와 상태 변화를 시각적으로 이해하는 데 도움을 주고 특히 복잡한 객체의 동작을 추적하고 이해하는 데 유용
      • Activity diagram
        • 시스템 내에서 흐름 제어, 동작 및 상호작용을 시각적으로 표현
        • 프로세스나 작업의 흐름을 단계별로 표현하여 시스템의 동작을 더욱 자세히 설명
        • 주로 비즈니스 프로세스, 사용자 시나리오, 시스템 동작 등을 나타내는 데 사용

객체지향 (소프트웨어 공학)




소프트웨어 공학 분야에서 객체지향 기술은 오래전부터 여러 분야에서 연구가 되어 왔던 아이템이다. 특히 1990년대부터 소프트웨어 분야에서는 매우 중요한 기술로 다뤄지며 생산성에 초점을 맞춘 프로그래밍 분야에서는 이제는 빼놓을 수 없는 핵심기술이다. 이는 소프트웨어의 발전이 하드웨어를 따라가지 못한다는 ‘소프트웨어 위기’를 타개할 수 있는 방법으로서 이제는 개발 주류가 된 객체지향은 특수화되고 적절하게 변경이 되며 소프트웨어 부품을 보다 체계적으로 다시 사용할 수 있는 인프라가 되었다.

 

객체지향 특징

객체지향의 특징은 무엇보다도 절차적인 프로그램과의 차이점을 보면 명확해진다.

🚩 모형의 적합성
복잡해지는 문제를 잘 모델링하기 위해서는 부분적인 자세함도 필요하지만 적절하게 자세한 것을 생략할 수 있는 추상화도 가능하여야 한다. 이는 객체지향에서 정보은닉과 메시지 교환이라는 개념을 활용하여 작업이 분산되고 감춰진다. 함수의 집합으로 구성된 절차적인 프로그래밍과 달리 객체지향 프로그램은 내부가 감춰진 객체들의 상호작용으로 구성된다. 그래서 자료를 따로 가진 객체들이 필요할 때만 협력한다. 더불어 개념이나 실체를 이산적인 객체로 모델링하여 독립된 객체로서 구현시킨다.

🚩 재사용 용이
재사용이 쉽다. 객체는 열림 특성과 닫힘 특성을 모두 갖추고 있고 재사용 부품으로서 그 역할을 한다. 닫힘은 변하지 않는 부분은 손대지 않고 그대로 다시 사용하는 것을 말하며 열림은 그 반대로 이를 변경 또는 확장하여 사용할 수 있는 것이다. 이를 가능하게 하는 개념은 바로 상속과 다형성이다. 추상화 클래스를 정의하고 파라미터를 용도에 맞게 사용할 수도 있고 캡슐화된 클래스를 그대로 쓰면서 필요에 따라 확장도 가능한 것이다.

🚩 Time to market
소프트웨어의 효율성 외에도 품질이나 유지보수 용이성, 시장 출하 시점도 소프트웨어 설계에 있어 매우 주요한 설계 기준이다. 시장에 처음 출시된 제품이 나중에 나온 제품보다 기능이 떨어지더라도 시장을 선점하고 점유한 상태를 무시할 수 없기 때문이다. 객체지향은 재사용이 용이하고 재설계가 필요 없기 때문에 개발기간을 단축할 수 있고 필요시 원하는 시점에 맞춰 제품 출하를 가능하게끔 하는 기술이다.

🚩 설계와 프로그래밍 매핑
절차적 방법에 비해 설계단계에서 프로그래밍으로의 전환이 매우 순조롭다. 즉 쉽게 매핑될 수 있다는 것인데 프로그램의 기초 단위인 객체나 클래스 개념을 말하는 것이다. 물론 코딩 자체는 다소 어려울 수 있더라도 분석 설계 단계에서 부분적인 코딩이 자유로운 객체지향은 모델링 기초 개념이 동일하여 이 또한 개발기간을 단축할 수 있는 결과를 가져올 수 있다.

 




기본개념

🚩 객체(Object)
객체는 현실 세계의 개체나 개념을 소프트웨어적으로 모델링한 것이다. 즉 필요한 자료구조와 이에 수행되는 함수들을 가진 하나의 소프트웨어 모듈로 볼 수 있다. 이는 자료구조를 갖고 상태를 가진다는 것인데 데이터와 해당 데이터를 처리하는 메소드(함수)를 함께 포함한다. 예로, 자동차 객체는 브랜드, 모델, 속도 등의 데이터와 가속, 정지와 같은 동작을 수행하는 메소드로 구성된다. 결국 객체는 상태와 행위, 정체성을 갖는, 비슷한 객체의 구조와 행동이 공통 클래스로 선언된다.

🚩 클래스(Class)
클래스는 객체를 생성하기 위한 템플릿이며 객체의 구조와 행동을 정의한다. 즉 객체의 타입이 클래스이다. 클래스는 속성(변수)과 메소드(함수)로 구성되며 객체를 생성할 때 이러한 속성과 메소드가 해당 객체에 포함된다. 자동차 클래스는 자동차 객체들이 가져야 할 속성과 메소드를 정의하는 것이 그 예이며 클래스에 속하는 객체를 이 클래스의 인스턴스라고 한다. 이런 클래스를 정의하기 위해서는 클래스가 가지는 속성을 도출하여야 한다. 다시 말해 클래스는 객체들이 갖는 속성과 적용 연산을 정의하고 있는 템플릿이다.

🚩 캡슐화(Encapsulation)
캡슐화는 객체의 상태(속성)와 행동(메소드)을 하나의 단위로 묶는 것이다. 객체는 외부에서 직접 접근하는 것을 제한하고 객체의 내부 동작을 숨기는 것으로 정보은닉을 지원하는데 이를 통해 객체의 내부 구현 세부 사항을 감추고 외부에서는 필요한 인터페이스를 통해 상호 작용할 수 있다. 캡슐화는 설계나 분석 단계에서 주어진 문제를 간단히 처리할 수 있는 추상화의 수단이 된다.

🚩 상속(Inheritance)
상속은 클래스 간의 계층 구조를 만들어 기존 클래스의 속성과 메소드를 다른 클래스가 상속받아 재사용할 수 있게 해준다. 부모 클래스(상위 클래스 또는 기본 클래스)의 특징을 자식 클래스(하위 클래스 또는 파생 클래스)가 물려받아 확장하거나 수정할 수 있다. 이를 통해 코드 재사용성과 계층적 구조를 갖는 클래스들을 구성할 수 있다. 이런 상속은 슈퍼 클래스, 서브 클래스로 클래스를 세분화하며 객체가 갖는 특유의 속성들을 추가할 수 있다. 참고로 두 개 이상의 슈퍼 클래스에서 상속받는 것을 복수 상속이라 한다.

🚩 다형성(Polymorphism)
다형성은 같은 이름의 메소드를 다양한 객체에서 호출할 때 다른 동작을 수행하도록 하는 개념으로 여러 가지 형태를 가지고 있다는 말이다. 이는 상속과 연결되어 있으며, 자식 클래스는 부모 클래스의 메소드(특정한 클래스를 위해서 오퍼레이션을 구현한 것)를 오버 라이딩(재정의)하여 자신에 맞게 수정할 수 있다. 다형성을 통해 객체 간의 유연하고 일관된 상호작용을 가능하게 한다. 다형성은 현재 코드를 변경하지 않고 새로운 클래스를 쉽게 추가할 수 있다.

 




객체지향 프로세스

객체지향 프로세스의 단계들은 선형적인 순서로 진행되는 것이 아니라 실제 개발 과정에서는 반복되거나 중첩되는 경우가 많다. 이는 소프트웨어 개발의 복잡성을 다루기 위해 계획, 설계, 구현, 검증, 유지보수 등을 체계적으로 수행하여 효율적이고 유지보수가 가능한 소프트웨어를 만들기 위한 접근법으로 큰 틀에서는 일반적인 소프트웨어 개발 프로세스와 동일하다.

✔️ 요구사항 분석
프로젝트의 목적과 필요한 기능을 파악하고 문서화한다. 이 단계에서는 사용자와 고객의 요구사항을 파악하고 이를 객체와 클래스로 변환하여 소프트웨어의 주요 기능과 특성을 정의한다. 주요 과정으로는 요구추출 단계에서는 액터, 시나리오, 여러 사례들을 찾고 구체화하며 여러 사례 간의 관계를 바탕으로 비기능적 요구를 명확화한다. 이후 요구분석을 통해 분석모형을 위한 객체, 객체 간 모형화, 연관관계, 속성 등을 찾고 정리한다.

✔️ 시스템 설계
요구사항을 바탕으로 시스템의 구조와 아키텍처를 설계한다. 클래스와 객체의 관계, 데이터베이스 구조, 인터페이스 등을 정의하고 시스템의 전체적인 동작 방식을 계획한다. 즉 설계목표를 정의하고 서브 시스템을 파악하고 여러 저장소를 설계하며 이를 패키지 다이어그램으로 정리한다.

✔️ 클래스 설계
시스템 설계를 바탕으로 클래스와 객체의 세부 사항을 설계한다. 클래스의 속성과 메소드를 식별하고 클래스 간의 관계를 설정하며 적절한 상속 구조를 설계한다. 객체를 정의하고 부품의 선택과 최적화를 통해 설계를 진행하며 상세화된 클래스 다이어그램을 작성한다.

✔️ 구현 및 테스트
클래스 설계를 기반으로 실제 코드를 작성한다. 각 클래스의 메소드를 구현, 데이터를 처리하며 객체들을 생성하고 관리한다. 이 단계에서는 객체지향 프로그래밍 언어를 사용하여 클래스와 메소드를 코드로 표현한다. 그리고 작성한 코드를 검증하여 시스템이 요구사항을 충족하는지 확인한다. 단위 테스트, 통합 테스트, 시스템 테스트 등 다양한 수준의 테스트를 수행하여 버그를 찾고 수정한다.

✔️ 배포 및 유지보수
개발한 소프트웨어를 배포하고, 사용자가 실제로 사용하면서 발생하는 문제를 해결하고 기능을 추가 또는 개선한다. 유지보수 단계에서는 시스템의 변경이나 업데이트가 필요한 경우 이를 수행한다.

✔️ 문서화, 평가와 개선
프로세스의 각 단계에서 만든 문서들을 정리하고 보완하여 개발된 소프트웨어의 설명서를 작성한다. 프로젝트가 완료된 후에는 전체 프로세스를 돌아보고 개발한 시스템의 성능과 사용성을 평가한다. 이를 통해 개선점을 발견하고 다음 프로젝트에 반영하기 위한 교훈(lessons learned)을 얻는다.




설계3 (소프트웨어 공학)

프로그램 설계

프로그램 설계(Programming Design)는 소프트웨어 공학의 개발 과정 중 하나로, 시스템의 각 모듈 안에서 일어나는 일들과 모듈 안에서의 자료구조에 관하여 설계하는 단계이다. 각 모듈 안에 사용될 알고리즘을 고안하는데 이는 소프트웨어 개발에서 설계 도면과 같은 역할을 한다. 이런 프로그램 설계는 시스템 구조설계와 분리하여 별도의 단계로 추진하기도 하지만 때로는 병행 진행하기도 한다. 프로그램 설계는 효율적이고 유지보수가 가능한 소프트웨어 시스템을 만들기 위해 필수적인 활동이며 요구사항 분석을 바탕으로 시스템의 목표를 이루기 위한 적절한 아키텍처와 구조를 결정하는 것으로서 잘 설계된 소프트웨어 시스템은 확장성, 유지보수성, 재사용성 등을 갖추어 복잡한 프로젝트의 성공을 보장하는 데 도움을 준다. 이에 프로그램 설계는 크게 두 가지 측면에서 이루어진다.

  • 구조적 설계: 시스템을 하위 모듈로 분할하고 각 모듈 간의 인터페이스와 관계를 정의한다. 모듈은 기능적으로 관련된 작업을 수행하는 코드 블록으로 소프트웨어 시스템을 조직화하는 데 사용되며 시스템 전체적인 레이아웃을 계획하고 모듈 간의 데이터 및 제어 흐름을 결정하는 역할이다.
  • 상세 설계: 구조적 설계 완료 후, 각 모듈의 내부 동작 및 구현 세부 사항을 정의하는 단계로 모듈 내부의 변수, 함수, 알고리즘 등을 설계하며 코드의 실제 구현 방식을 결정한다. 이는 실제 프로그래밍 단계에 진입하기 전에 개발자들이 따라야 할 로드맵을 제공한다.

구조적 설계에 이어 상세설계 단계는 모듈을 하나씩 다룬다. 각 모듈을 구현하기 위한 알고리즘을 선택하고 기술하는 것이다. 시스템 구조설계가 잘 이루어진 상태라면 각 모듈 안의 설계는 어렵지 않다. 각 모듈의 역할이 분명하고 모듈 사이의 결합도가 낮게 구성되기 기 때문이다. 설계의 원리들을 따 잘 설계하였다면 모듈을 어떻게 구현할 것인가를 결정하는 일은 알고리즘 선택으로 국한된다.




알고리즘 선택

알고리즘 선택의 3가지 원칙은 다음과 같다.

  • 정확성: 알고리즘은 기본적으로 정확해야 한다. 기술된 알고리즘은 제공된 자료를 정확하게 처리하여야 하며 정의된 기능 또한 정확하게 수행하여야 한다. 이런 상황에서 모듈이 수행하여야 할 기능이 새로운 것이 아니라면 기존의 프로그램이나 알고리즘 모음집 등의 자료를 참고하는 것도 좋은 방법이다. 프로그램을 처음부터 새로 구현하는 것보다 증명된 알고리즘을 사용하거나 이미 수행된 프로그램을 사용하면 개발비용과 시간을 절약할 수 있다.
  • 효율성: 알고리즘의 수행에 필요한 컴퓨터 자원의 양을 말한다. 이는 기억장치의 소요량과 수행시간이다. 특히 수행시간은 알고리즘과 밀접한 관계가 있다. 알고리즘의 기본 동작 수는 알고리즘에 따라 선형적일 수도 있고 비선형적일 수도 있다. 같은 문제에 대해서 접근법이 다르다면 그 결과는 천차만별이다. 즉 효율성을 높이면 처리 속도는 매우 크게 개선되며 모듈 안에서의 효율성과 전체 시스템의 효율성을 같이 고려하여 알고리즘을 구현해야 한다.
  • 적합성: 알고리즘은 목표 시스템의 하드웨어와 소프트웨어에 맞아야 한다. 이는 시스템의 특성, 목표, 제약조건 등을 충분히 감안하여 그 방향성에 맞춰 알고리즘을 구사하여야 한다. 설계단계의 모든 것이 고려되어야 하며 필요시 보다 맞는 알고리즘으로 대체할 수 있는 계획을 가지고 있어야 한다.

알고리즘 표현

설계단계에서 사용되는 모든 표현법은 매우 중요하다. 이는 의도하는 바를 정확하게 나타낼 수 있고 의사소통을 원활하게 해준다. 모듈 안 알고리즘을 기술하는 방법도 여러 가지가 있다.

  • 나씨-슈나이더만도표(Nassi-Shneiderman Diagram): 제어 구조를 시각적으로 표현하는 것으로 제어 흐름을 명확하게 표현하여 프로그램의 논리를 이해하고 분석하는데 순차, 선택, 반복과 같은 기본적인 제어 구조를 사용하여 알고리즘을 표현
  • 자연어: 일반적인 언어를 사용하여 알고리즘을 설명하는 것으로 비기술적인 사람들도 쉽게 이해할 수 있으나 그 모호성이나 해석 차이로 인해 정확한 이해를 보장하지 않을 수 있음
  • 순서도(Flowchart): 도형과 화살표를 사용하여 알고리즘의 흐름을 시각적으로 나타내는 것으로 시작과 종료 점, 결정, 처리, 입출력 등의 기호로 표현하여 알고리즘의 논리 구조를 표현
  • 의사 코드(Pseudo code): 일반 언어와 프로그래밍 언어의 중간 형태로 인간이 이해하기 쉬운 형태의 코드이며 실제 프로그래밍 언어가 아니므로 특정 구문이나 규칙에 얽매이지 않고 알고리즘의 논리적 흐름을 설명 가능
  • 프로그래밍 언어: 알고리즘을 실제 프로그래밍 언어로 구현하여 나타내는 방법으로 컴퓨터가 직접 실행할 수 있도록 하며 알고리즘의 구현 세부 사항을 정확히 표현 가능
  • 통합 모델링 언어(UML: Unified Modeling Language): 주로 소프트웨어 설계와 모델링에 사용되며 다이어그램을 사용하여 시스템의 구조와 동작을 표현하고 클래스 다이어그램, 시퀀스 다이어그램, 상태 다이어그램 등을 활용
  • 스토리보드: 주로 사용자 인터페이스 설계에서 활용되며 그림과 텍스트를 사용하여 사용자와 시스템 간의 상호작용 흐름을 시각적으로 표현

 




사용자 인터페이스 설계

사용자 인터페이스 설계(User Interface Design)는 소프트웨어 공학에서 사용자와 소프트웨어 시스템 간의 상호작용을 디자인하는 과정으로 사용자가 시스템과 소통하는 방식을 결정하고 설계한다. 사용자 인터페이스는 시스템의 기능을 사용자가 이해하고 조작할 수 있도록 돕는 중요한 요소이며 사용자 만족을 전제로 한다. 이에 사용자 인터페이스에 대한 평가 요소가 중요하며 특히 배우기 쉬워야 하고 반응속도가 좋고 사용 중 오류의 빈도가 낮아야 하며 사용자를 만족시키고 사용법을 계속 유지해야 하는 점이 강조된다. 이를 모두 만족시키는 것이 이상적이기는 하나 중요한 사항을 선택적으로 충족시키는 경우도 많다. 이에 사용자 요구사항에 대한 우선순위를 고려하여 높은 우선순위부터 사용자 만족을 충족시키는 형태로 개발해야 한다. 이에 사용자 인터페이스 설계는 다음과 같은 목표를 갖는다.

  • 사용자 친화성: 인터페이스는 사용자가 직관적으로 이해하고 사용할 수 있도록 설계되어야 하며 사용자가 복잡한 기능을 쉽게 찾고 사용할 수 있도록 지원
  • 효율성: 인터페이스는 사용자가 작업을 빠르게 수행하고 목표를 달성해야 하며 불필요한 클릭이나 탐색을 최소화하여 작업의 효율성 보장
  • 일관성: 인터페이스 요소들은 일관된 디자인과 동작을 가져야 하며 사용자가 유사한 기능을 다양한 부분에서 일관되게 경험할 수 있도록 작업 
  • 피드백과 가시성: 사용자의 작업에 대한 적절한 피드백과 시각적인 표시를 제공하여 사용자가 자신의 작업을 추적하고 이해할 수 있도록 작업
  • 유연성: 다양한 사용자 요구와 환경을 고려하여 다양한 장치와 환경에서 작동할 수 있는 인터페이스 고려

좋은 사용자 인터페이스 설계는 소프트웨어 제품의 성공과 사용자 만족도에 큰 영향을 미치며 사용자들의 요구와 행동을 고려하여 개발되어야 하는데 보통은 다음과 같은 단계로 진행된다.

  • 요구사항 분석
    • 사용자의 요구사항과 기대를 이해하고 문서화
    • 사용자 그룹을 식별하고, 사용자의 특성, 선호도, 작업 환경 등 파악
    • 시스템의 목적과 기능, 사용자의 목표 정의
  • 설계 및 기획
    • 사용자 경험(UX)을 중심으로 설계
    • 인터페이스의 레이아웃, 구조, 흐름 계획
    • 기능적 요구사항을 각각의 화면 또는 모듈 매핑
    • 정보 구조를 설계하고, 사용자가 쉽게 찾아서 사용할 수 있도록 계획
  • 프로토타이핑
    • 초기 디자인 아이디어를 실제로 시뮬레이션하는 프로토타입 개발
    • 프로토타입을 사용하여 사용자의 피드백을 수집하고, 문제점이나 개선 사항 확인
    • 프로토타입을 통해 디자인과 기능을 검증하며, 수정과 보완 진행
  • 디자인
    • 프로토타입을 기반으로 시각적인 디자인 수행
    • 색상, 아이콘, 글꼴 등을 선택하여 사용자가 시각적으로 쉽게 인터페이스를 이해할 수 있도록 가이드
    • 일관성 있는 디자인 가이드라인을 따르면서 사용자가 헷갈리지 않도록 지침제시
  • 개발
    • 디자인된 인터페이스를 실제 코드 구현
      사용자 인터페이스 요소들을 프로그래밍 언어와 기술을 사용하여 구현
  • 테스트
    • 인터페이스의 기능, 사용성, 성능 테스트
    • 버그, 오작동, 일관성 문제 등을 식별하고 수정
    • 다양한 시나리오와 테스트 케이스를 사용하여 인터페이스 검증
  • 사용자 피드백 수집
    • 완성된 인터페이스를 실제 사용자들에게 제공하고 피드백 수집
    • 사용자의 의견을 수렴하여 인터페이스를 개선 보완
  • 배포 및 유지보수
    • 최종적으로 개발된 사용자 인터페이스 배포
    • 사용자들의 피드백을 기반으로 지속해서 개선과 보완 작업 수행

설계2 (소프트웨어 공학)

소프트웨어 공학에서 구조적 설계는 소프트웨어 시스템을 개발할 때 전체 시스템의 구조와 구성 요소 간의 상호작용을 계획하고 설계하는 단계이다. 이는 소프트웨어 개발 프로세스의 중요한 부분으로 시스템의 복잡성을 다루며 유지보수할 수 있고 확장할 수 있는 소프트웨어 시스템을 만들기 위한 첫 번째 큰 단계 중 하나다. 이러한 구조적 설계는 앞서와 같이 모듈화와 추상화, 모듈 간 인터페이스 설계, 데이터 구조 설계, 제어구조 설계, 자료구조 설계 및 모듈의 응집도와 결합도 등으로 구성되어 있다. 특히 구조적 프로그래밍을 통해 GOTO 문을 최소화하고 대신 조건문과 반복문 등을 사용하여 프로그램 흐름을 명확하게 구조화한다. 이는 코드의 가독성과 디버깅 효율을 높이는 좋은 방법이다. 또한 일반적인 소프트웨어 설계 문제에 대한 해결책으로 사용되는 디자인 패턴을 활용하여 설계의 일관성과 재사용성을 향상한다.

구조적 설계는 소프트웨어의 크기와 복잡성을 관리하고 효율적인 개발 및 유지보수를 가능하게 해주는 중요 단계다. 이를 통해 개발자는 요구사항을 충족하면서도 확장 가능하고 품질 좋은 소프트웨어 시스템을 개발할 수 있다.

 




구조적 설계

구조적 분석은 설계 결과를 구조도로 나타낸다. 구조도는 시스템의 모든 모듈을 사각형의 박스로 표현하며 모듈의 호출 관계를 화살표로 나타내는 계층적 트리 형식의 표이다. 결국 소프트웨어 구조도는 시스템을 어떤 모듈들로 나누었는가를 명시적으로 나타내며 모듈들의 계층구조와 모듈 간 입출력, 인터페이스, 기능을 나타내는 이름들을 보여준다. 이러한 시스템 구조는 전체적으로 치우침 없는 균형을 이뤄야 한다. 그렇지 못한 경우 처리에 병목현상이 발생한다. 균형은 구조도의 폭과 깊이, 입출력 또는 처리 편중, 영향 범위 등에 의해서 결정된다. 시스템 구조도가 불균형인 경우 모듈의 역할이나 규모를 다시 나누어 균형을 이루도록 해야 한다.

구조의 깊이는 시스템 구조도의 레벨 수다. 깊이는 모듈 사이에서 호출하고 반환하는 과정이 길게 이어진다는 뜻이다. 따라서 깊이가 깊어지면 최하위 모듈까지 통신에 대한 부하가 늘어난다. 또한 구조의 넓이는 상위 모듈이 호출하는 모듈의 개수이다. 이를 보통 Fan-out이라 하며 한 모듈에서 호출하는 하위 모듈이 너무 많으면 호출하는 모듈이 제어할 때 병목 현상이 생길 수 있다. 제어의 범위를 너무 크지 않게 하는 것이 운용의 묘를 살리는 것이며 이 또한 매직넘버 7 내외를 유지하는 것이 좋고 이것이 Fan-out 수다. 여기서 호출하는 모듈수를 줄이려면 중간층의 모듈을 몇 개 두어 중간 모듈이 하위 모듈을 호출하도록 한다. 또한 하위 모듈 중 그룹화할 수 있는 모듈이 있거나 다른 모듈 등이 있다면 이를 분리한다.

구조적 설계는 분석 단계에서 생성된 자료 흐름도를 활용하여 소프트웨어 구조를 추출한다. 이에 두 가지 방법으로서 변환분석과 처리분석으로 구조를 추출한다. 

  • 변환분석(Transformation Analysis): 소프트웨어 시스템 내 데이터 변환과 이동을 분석하는 과정으로 시스템 모듈 간 어떻게 데이터가 전달되고 가공되는지를 파악하여 시스템의 데이터 흐름을 이해한다. 이를 통해 시스템의 기능과 동작을 정확하게 파악하고 데이터 변환 과정에서 발생할 수 있는 오류나 문제를 사전에 예측하고 방지할 수 있다. 
    • 데이터 흐름 다이어그램(DFD) 작성: 시스템 내의 데이터 흐름을 그래픽으로 표현하는 도구인 데이터 흐름 다이어그램을 작성한다. 다이어그램은 프로세스, 데이터 저장소, 데이터 흐름 등을 나타내어 시스템의 데이터 흐름을 시각화한다.
    • 프로세스 식별과 정의: 시스템 내의 각각의 프로세스(기능 또는 서비스)를 식별하고, 그들이 어떤 데이터를 입력으로 받고 어떤 데이터를 출력으로 생성하는지를 정의합니다.
    • 데이터 변환 및 가공 분석: 각 프로세스 내에서 데이터가 어떻게 변환되고 가공되는지를 분석합니다. 데이터의 가공 단계에서 발생할 수 있는 오류나 일관성 문제를 식별하고 이에 대한 대비책을 마련합니다.
    • 데이터 저장소 식별과 정의: 데이터 흐름 중간에 위치하는 데이터 저장소(파일, 데이터베이스 등)를 식별하고, 이들이 어떤 데이터를 저장하고 어떤 프로세스에 의해 엑세스되는지를 정의합니다.
  • 처리분석(Transaction Analysis): 소프트웨어 시스템 내에서 발생하는 트랜잭션을 분석하는 과정으로 시스템 사용자와 시스템 간의 상호작용을 이해하고 각각의 트랜잭션이 어떤 데이터와 기능을 요구하며 어떤 결과를 반환하는지를 파악한다. 이로써 시스템의 기능 요구사항을 정확히 파악하고 시스템의 응답 시간과 성능을 평가할 수 있다.
    • 트랜잭션 식별과 정의: 시스템 사용자의 작업 또는 요청을 트랜잭션으로 식별하고 각 트랜잭션이 어떤 데이터와 기능을 요구하는지 정의
    • 트랜잭션의 처리 흐름 분석: 각 트랜잭션이 어떤 프로세스나 모듈을 통해 처리되는지를 분석하며 트랜잭션의 처리 흐름을 파악하여 성능 병목 현상이나 오류 발생 가능성을 예측하고 대비책을 마련
    • 트랜잭션의 성능 분석: 각 트랜잭션의 응답 시간, 처리량 등의 성능을 분석하여 사용자 요구사항을 충족시킬 수 있는지 평가

 




소프트웨어 구조

흔히 스타일이라고 하면 설계와 시공을 위한 큰 밑그림을 그리는데 여기서 일관된 모양과 조화를 뜻한다. 이 스타일을 소프트웨어 구조에서도 사용할 수 있다. 소프트웨어 시스템이 복잡해지면서 시스템의 구조 문제는 더욱 중요해졌는데 왜냐면 일단 개발이 시작되면 이후 잘못된 부분을 바로잡기가 쉬지 않기 때문이다. 이런 문제의 중요성을 인식하여 소프트웨어 구조 개념이 나타났다. 소프트웨어 구조는 시스템 분할, 전체 제어 흐름, 오류처리 방침, 서브 시스템 간 통신 프로토콜을 포함한다. 이에 몇 가지 주요 스타일이 무엇이 있는지 살펴볼 필요가 있다.

  • 저장소 (Repository) 구조: 소스 코드, 문서, 데이터 등의 자원을 중앙 집중화하여 관리하는 구조로 팀원들은 동시에 작업하거나 버전을 관리하며 변경 사항을 추적할 수 있다. 버전 관리 시스템(VCS)인 Git과 같은 도구가 이 구조의 핵심 역할을 수행하며 이를 통해 협업과 코드 품질을 개선하며 변경 내역을 추적하여 문제를 해결하는 데 도움을 준다.
  • MVC (Model-View-Controller) 구조: 소프트웨어를 세 가지 주요 컴포넌트로 분리하여 구조화하는 패턴으로 코드의 재사용성, 유지보수성 및 확장성을 향상하며 시스템의 구성 요소 간의 결합 도를 낮추는 데 도움을 준다. 
    • Model: 데이터와 비즈니스 로직을 관리한다. 데이터의 상태와 조작 방법을 정의하고 시스템의 핵심 기능을 담당한다.
    • View: 데이터를 시각적으로 표현하는 역할을 한다. 데이터를 사용자에게 표시하거나 입력을 받을 수 있는 인터페이스를 제공한다.
    • Controller: 사용자의 입력을 처리하고 Model과 View 사이의 상호 작용을 조정한다. 사용자 요청을 해석하고 적절한 Model 업데이트 및 View 업데이트를 수행한다.
  • Client/Server 구조: 소프트웨어 시스템을 두 부분으로 분할하는 구조로 클라이언트는 사용자 인터페이스와 관련된 작업을 수행하고 서버는 데이터 처리 및 비즈니스 로직과 같은 작업을 수행한다. 클라이언트는 서버에 요청을 보내고 서버는 해당 요청을 처리하여 결과를 반환한다. 이 구조는 분산 처리 및 확장성을 가능하게 하며 다양한 플랫폼과 기기 간의 상호작용을 지원하는 가장 기초적인 구조이다.
  • 계층 (Layered) 구조: 시스템을 여러 계층으로 나누어 각 계층이 특정 기능을 수행하도록 하는 구조로 각 계층은 자신 바로 아래 계층과 상호작용하며 상위 계층은 하위 계층을 직접적으로 몰라도 된다. 이 구조는 코드의 모듈화와 재사용을 촉진하며 시스템의 유지보수 및 확장성을 개선하는 데 도움을 준다.
  • 파이프-필터 (Pipe-Filter) 구조: 데이터 처리를 여러 단계로 나누어 각 단계를 필터로 생각하고 각 단계 간 데이터를 파이프로 연결하여 처리하는 구조로 각 필터는 특정 작업을 수행하며 데이터를 받아 처리한 후 결과를 다음 필터로 전달한다. 이 구조는 시스템의 기능을 모듈화하고 데이터 처리를 효율적으로 관리하는 데 도움을 준다.