<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>charlie_dev.log</title>
        <link>https://velog.io/</link>
        <description>찬찬히 써내려가는 개발일지</description>
        <lastBuildDate>Tue, 26 May 2026 13:17:58 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>charlie_dev.log</title>
            <url>https://velog.velcdn.com/images/woong_crouch/profile/ae9426fe-b4b0-496d-bfa3-954b81125b04/image.gif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. charlie_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/woong_crouch" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[SW Engineering & Testing (12) - Integration Testing]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-12-Integration-Testing</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-12-Integration-Testing</guid>
            <pubDate>Tue, 26 May 2026 13:17:58 GMT</pubDate>
            <description><![CDATA[<h1 id="introduction">Introduction</h1>
<h2 id="ieee-표준-결함-유형과-통합-테스팅의-타겟">IEEE 표준 결함 유형과 통합 테스팅의 타겟</h2>
<p>IEEE Standard Classification(1993)에 따르면 소프트웨어 결함은 여러 가지로 분류되는데, 테스트 단계별로 타겟팅하는 결함이 다르다.</p>
<h3 id="1-단위-테스팅unit-testing의-타겟">1. 단위 테스팅(Unit Testing)의 타겟</h3>
<p>주로 화이트박스 및 데이터 흐름 테스팅을 통해 내부 로직 결함(Logic Faults), 계산 결함(Computation Faults), 데이터 결함(Data Faults) 등을 잡아냅니다.</p>
<h3 id="2-통합-테스팅integration-testing의-타겟">2. 통합 테스팅(Integration Testing)의 타겟</h3>
<p>모듈들이 결합될 때 발생하는 &#39;인터페이스 결함(Interface Faults)&#39;을 찾아내는 데 집중한다.</p>
<p><strong>인터페이스 결함의 구체적 종류</strong></p>
<ul>
<li>타이밍 오류 (<code>I/O timing</code>)</li>
<li>잘못된 프로시저 호출 (<code>Call to wrong procedure</code>)</li>
<li>존재하지 않는 프로시저 호출 (<code>Call to nonexistent procedure</code>)</li>
<li><strong>파라미터 불일치</strong> (<code>Parameter mismatch (type, number)</code>)</li>
<li><strong>호환되지 않는 타입</strong> (<code>Incompatible types</code>).</li>
</ul>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/a61bd231-21f6-4de8-b306-6bb8161590e3/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/b90fd88c-0f54-45f7-ad1c-541ea3b5e037/image.png" alt=""></th>
</tr>
</thead>
</table>
<h2 id="interface-testing">Interface testing</h2>
<p><strong>Interface testing</strong>의 목적은 모듈 간 인터페이스의 직접적인 오류나, 인터페이스에 대한 잘못된 가정(Invalid assumptions)으로 인해 발생하는 결함을 감지하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e8a801d3-7aab-4203-9972-9fa22554ece9/image.png" alt=""></p>
<h3 id="1-interface-misuse-인터페이스-오용--잘못된-사용">1) Interface misuse (인터페이스 오용 / 잘못된 사용)</h3>
<p>호출하는 컴포넌트(Calling component)가 다른 컴포넌트를 호출할 때 인터페이스 사용에 물리적/구문적 실수를 하는 경우를 말한다.</p>
<p>주로 시스템이 정해둔 규칙을 <strong>개발자가 코딩 과정에서 단순하게 틀리게 작성한 경우</strong>를 말한다. 가장 흔한 예시로 <strong>파라미터(매개변수)의 순서를 뒤바꿔서 전달</strong>하거나, 정수(int)를 넣어야 할 자리에 문자열(string)을 넣는 등의 실수가 여기에 해당한다.</p>
<h3 id="2-interface-misunderstanding-인터페이스-오해--잘못된-이해">2) Interface misunderstanding (인터페이스 오해 / 잘못된 이해)</h3>
<p>호출하는 컴포넌트가 호출받는 컴포넌트의 동작 방식에 대해 <strong>부정확하고 잘못된 가정(Assumptions)을 내포</strong>하고 있는 경우를 말한다.</p>
<p>파라미터의 타입이나 순서는 맞아서 <strong>프로그램 자체는 에러 없이 돌아가지만, 그 안의 &#39;의미(논리)&#39;를 서로 다르게 해석하여 발생하는 문제</strong>를 생각해볼 수 있다. </p>
<p>대표적인 사례로 <strong>NASA의 화성 기후 궤도선 폭발 사고</strong>(Mars Climate Orbiter Accident)가 있다. 이 사고는 록히드 마틴은 &#39;파운드&#39; 단위로 데이터를 넘겼는데, NASA는 이를 &#39;미터법(뉴턴)&#39; 단위일 것이라고 &#39;잘못된 가정&#39;을 한 채로 모듈을 결합했다가 우주선이 폭발해버린 사례이다.</p>
<h3 id="3-timing-errors-타이밍-오류">3) Timing errors (타이밍 오류)</h3>
<p>호출하는 컴포넌트와 호출받는 컴포넌트의 <strong>작동 속도(Speed)가 달라서, 오래된(Out-of-date) 정보에 접근</strong>하게 되는 문제를 말한다.</p>
<p>두 개 이상의 모듈이 동시에 실행되는 환경(특히 실시간 시스템이나 병렬 처리 시스템)에서 주로 발생한다. 예를 들어, 모듈 A가 새로운 센서 값을 아직 데이터베이스에 업데이트(저장)하지도 않았는데, 모듈 B가 한발 앞서서 데이터베이스를 읽어버려 <strong>과거의 낡은 값을 바탕으로 잘못된 제어 명령을 내리는 동기화 문제</strong>가 이에 해당한다.</p>
<h3 id="4-사례--화성-기후-궤도선-사고-mars-climate-orbiter-accident">4) 사례 : 화성 기후 궤도선 사고 (Mars Climate Orbiter Accident)</h3>
<p>1998년 12월에 발사된 338kg의 로봇 우주 탐사선이 41주 동안 4억 1,600만 마일을 날아간 후 1999년 9월에 완전히 실종(파괴)되었다.</p>
<h4 id="사고-원인-의사소통-및-인터페이스-오류">사고 원인 (의사소통 및 인터페이스 오류)</h4>
<p>스템을 공동 개발한 <strong>NASA와 록히드 마틴(Lockheed) 간의 의사소통 오해</strong> 때문에 발생했으며, 한쪽(록히드 마틴)은 <strong>파운드(Pound Unit)</strong> 단위를 사용하여 추력 데이터를 계산해 넘겼고 다른 한쪽(NASA)은 이를 <strong>뉴턴(Newton Metric Unit)</strong> 미터법 단위로 착각하여 받아들였다.</p>
<p>즉, 개별 모듈(단위)은 완벽하게 작동했을지라도, 모듈 간 데이터를 주고받는 <strong>인터페이스 단계에서 단위(Type)에 대한 잘못된 가정</strong>을 테스트로 걸러내지 못해 막대한 비용이 투입된 우주선이 폭발해버린 통합 결함의 대표적 사례이다.</p>
<h1 id="integration-testing통합-테스팅">Integration Testing(통합 테스팅)</h1>
<p>개별 모듈들이 결합되었을 때 <strong>모듈 간의 상호작용(Interactions among modules)이 올바르게 일어나는지</strong>에 초점을 맞춘다. 통합 테스팅은 명세서(Specification)를 바탕으로 테스트 케이스를 도출하는 <strong>블랙박스 테스팅(Black-box testing)으로 수행</strong>되어야 한다.</p>
<p>결함이 발생했을 때 <strong>오류의 정확한 위치를 파악(Localising errors)하는 것</strong>이 어려움으로 작용하고 이를 해결하는 방법으로는 <strong>점진적 통합 테스팅(Incremental integration testing)</strong> 이 존재한다. 이는 <strong>모든 모듈을 한 번에 결합하지 않고 점진적으로 추가하는 방식</strong>이다.</p>
<p>통합 테스팅은 아래의 네가지 접근법을 가진다.</p>
<p><strong>1. Big Bang (빅뱅 통합)
2. Decomposition-based integration (분해 기반 통합)
3. Call Graph-based integration (호출 그래프 기반 통합)
4. Path-based integration (경로 기반 통합)</strong></p>
<h2 id="점진적-통합-테스팅-incremental-integration-testing">점진적 통합 테스팅 (Incremental Integration Testing)</h2>
<p>한 번에 모듈을 다 합치는 것이 아니라 단계별로 묶어서(Sequence) 테스트하는 방식으로, 자료의 다이어그램(A, B, C, D 모듈 결합)을 통해 이를 명확히 보여준다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/2245b825-a81e-44b8-b5c9-e8a2df520f03/image.png" alt=""></p>
<p>총 3가지의 Test Sequence로 나눠서 테스트를 수행하는 것을 예시로 설명하자면,
<strong>Test Sequence 1</strong>
모듈 A와 B를 결합하여 먼저 테스트(T1, T2, T3)를 수행한다.
<strong>Test Sequence 2</strong>
앞서 결합된 A, B 시스템에 모듈 C를 추가 결합하여 테스트(T1, T2, T3, T4)를 수행한다.
<strong>Test Sequence 3</strong>
마지막으로 모듈 D까지 전부 결합하여 테스트(T1, T2, T3, T4, T5)를 수행한다.</p>
<p>결과적으로 오류가 나더라도 새로 추가된 모듈과의 연결 부위를 의심하면 되므로 디버깅이 매우 쉬워지는 효과를 얻을 수 있다.</p>
<h2 id="분해-기반-통합-decomposition-based-integration">분해 기반 통합 (Decomposition-based Integration)</h2>
<p>시스템을 기능적으로 분해한 구조(트리 형태)를 바탕으로 결합하는 방식이며, 방향에 따라 3가지로 나뉜다.</p>
<h3 id="1-top-down-testing-하향식-테스팅">1) Top-down testing (하향식 테스팅)</h3>
<p>최상위(High-level) 시스템부터 시작하여 <strong>위에서 아래로(Top-down)</strong> 점진적으로 통합하는 방식을 말하고, 아직 개발되지 않은 하위 컴포넌트의 자리는 임시 가짜 모듈인 &#39;스텁(Stubs)&#39;으로 교체(replacing)하여 테스트하는 방식을 말한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/bc840035-aa22-4821-9dde-d44d20c6a5e8/image.png" alt=""></p>
<p>Level 1을 먼저 테스트하고, 하위 계층은 Level 2 stubs, Level 3 stubs로 대체하여 진행하는 것이다.</p>
<h3 id="2-bottom-up-testing-상향식-테스팅">2) Bottom-up testing (상향식 테스팅)</h3>
<p>최하위의 개별 컴포넌트부터 시작하여 <strong>아래에서 위로(Bottom-up)</strong> 점진적으로 결합해 완전한 시스템을 만든다. 하위 모듈을 호출해 줄 상위 모듈이 아직 없으므로, 이를 대신해 하위 모듈에 명령을 내리는 &#39;테스트 드라이버(Test drivers)&#39;가 필요하다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/78ff9695-f0bd-4924-9b13-817210d8b9d8/image.png" alt=""></p>
<p>Level N, Level N-1 모듈들을 최상단의 Test drivers가 제어하며 테스트한다.</p>
<h3 id="3-sandwich-integration-샌드위치-통합">3) Sandwich integration (샌드위치 통합)</h3>
<p>하향식(Top-down)과 상향식(Bottom-up) 통합 방식을 혼합(Combination)한 방식이다.</p>
<h2 id="실습-calendar-program-example-기능-분해-구조">실습: Calendar Program Example (기능 분해 구조)</h2>
<p>달력 프로그램의 통합 테스팅 실습을 위해 시스템을 다음과 같은 기능 트리(Functional decomposition)로 분해한다. 최상위 루트는 <strong><code>Calendar (Main)</code></strong> 이고, 하위 서브 모듈들은 아래의 리스트와 같다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/a1cff90b-b8c7-4a7f-b5a9-821d9edfacb0/image.png" alt=""></p>
<p><strong>하위 서브 모듈들:</strong></p>
<ul>
<li><code>isLeap</code>: 윤년 판별</li>
<li><code>weekDay</code>: 해당 날짜의 요일 계산 (Mon, Tue 등)</li>
<li><code>getDate</code>: 날짜 정보 가져오기 (하위에 <code>isValidDate</code> $\rightarrow$ <code>lastDayOfMonth</code> $\rightarrow$ <code>dateToDaynum</code> 과 <code>getDigits</code>를 가짐)</li>
<li><code>Zodiac</code>: 해당 날짜의 별자리 기호(Zodiac sign) 판별</li>
<li><code>nextDate</code>: 다음 날짜(NextDate) 계산</li>
<li><code>Friday13th</code>: 가장 최근의 13일의 금요일 찾기</li>
<li><code>Memorial day</code>: 5월 27일에 기념일이 열린 가장 최근 연도 찾기</li>
</ul>
<h2 id="calendar-program을-통한-3가지-통합-테스팅-적용">Calendar Program을 통한 3가지 통합 테스팅 적용</h2>
<p>앞서 나눈 달력 프로그램 구조를 하향식, 상향식, 샌드위치 방식으로 어떻게 테스트하는지 구체적으로 보여준다.</p>
<h3 id="①-top-down-하향식">① Top-down (하향식)</h3>
<p>최상단의 <code>Calendar (Main)</code> 모듈을 테스트하기 위해 하위 모듈인 <code>zodiac</code> 함수가 아직 완성되지 않았다고 가정한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e4b67ac4-b773-41bc-bbe5-751434254178/image.png" alt=""></p>
<p>이때 하위 모듈을 대체할 <strong>Test Stub(테스트 스텁)</strong> 을 작성하는데, 자료에서는 구체적으로 다음과 같은 C언어 스타일의 스텁 코드를 예시로 보여준다.</p>
<h3 id="②-bottom-up-상향식">② Bottom-up (상향식)</h3>
<p>최하위 모듈인 <code>zodiac</code>을 테스트하기 위해, 이를 호출해 줄 <strong>Test driver(테스트 드라이버)</strong> 인 <code>Calendar (driver)</code>를 임시로 만든다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/439f811b-d2b6-43a8-a8f6-218fd466315e/image.png" alt=""></p>
<p>여기서 핵심 포인트는 <strong>&quot;Test drivers are more complex than test stubs (테스트 드라이버가 스텁보다 만들기 훨씬 복잡하다)&quot;</strong> 는 점이다.</p>
<p>예를 들어, 별자리(<code>zodiac</code>)를 완벽히 테스트하려면 드라이버에서 <strong>총 36개의 테스트 케이스(Call zodiac : 36 TC (before, 0, after))</strong> 를 일일이 세팅하고 호출해 주어야 한다.</p>
<h3 id="③-sandwich-샌드위치">③ Sandwich (샌드위치)</h3>
<p>이 방식은 서브 트리(sub-tree) 단위로 <strong>빅뱅 통합(Doing big bang integration)</strong> 을 수행하는 것과 유사하다. 드라이버나 스텁 없이, 트리의 루트(root)부터 리프(leaves)까지 이어지는 <strong>전체 경로(A full path)</strong>를 한 번에 묶어서 테스트한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/54d4696e-cebb-44a7-bffc-e68841e28a1a/image.png" alt=""></p>
<p>모듈을 크게 묶어버렸기 때문에 오류가 발생했을 때 <strong>어느 모듈에서 문제가 생겼는지 격리하기가 매우 어렵다(It is difficult to isolate faults)</strong>는 치명적인 단점이 있다.</p>
<h2 id="호출-그래프-기반-통합-call-graph-based-integration">호출 그래프 기반 통합 (Call Graph-based integration)</h2>
<p>앞서 전반부에서 다룬 분해 기반(하향식, 상향식, 샌드위치) 통합 테스팅에 이어, 모듈 간의 호출 관계도(Call Graph)를 바탕으로 통합 테스팅을 진행하는 4가지 접근법 중 하나이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/dc6790e9-f316-4911-a4b7-7dc6b411dad2/image.png" alt=""></p>
<h1 id="system-testing">System Testing</h1>
<h2 id="1-시나리오-기반-테스팅-scenario-based-testing">1. 시나리오 기반 테스팅 (Scenario-based Testing)</h2>
<p>시스템 테스팅은 <strong>전체 시스템의 실제 요구사항이 잘 동작하는지 확인하는 단계</strong>로, &#39;시나리오 기반 테스팅&#39;이 주로 활용된다.</p>
<h3 id="1-유스케이스-다이어그램-use-case-diagram">1) 유스케이스 다이어그램 (Use Case Diagram)</h3>
<p><strong>사용자의 요구사항을 식별</strong>하여 Use Case Diagram을 작성한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/ed868140-0102-4d34-a31a-155ffb3a3be0/image.png" alt=""></p>
<p>예시로 나온 &#39;유명 미술품 딜러(오스버트)를 위한 관리 시스템&#39;에서는 오스버트, 판매자(Seller), 구매자(Buyer)라는 액터가 등장하며, &#39;그림 구매&#39;, &#39;그림 판매&#39;, &#39;보고서 생성&#39; 등의 유스케이스를 도출한다.</p>
<h3 id="2-유스케이스-명세-및-시나리오">2) 유스케이스 명세 및 시나리오</h3>
<p>&#39;명작 구매(Buy a Masterpiece)&#39; 시나리오를 보면, 설명 입력 → 경매 기록 스캔 → 유사 작품의 과거 낙찰가 기준 연 8.5% 복리를 가산하여 최대 구매가 산정 → 판매자 정보 입력과 같은 구체적인 흐름을 정의한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/61210ef6-81db-483d-b10f-730fc5cc3f62/image.png" alt=""></p>
<h3 id="3-시퀀스-다이어그램-sequence-diagram">3) 시퀀스 다이어그램 (Sequence Diagram)</h3>
<p>해당 유스케이스가 내부적으로 어떻게 동작하는지 명세한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e03d7013-fc66-48eb-85e1-d517b606b656/image.png" alt=""></p>
<p>판매자와 오스버트 사이에서 UI 클래스, 가격 계산 클래스, 경매 기록 데이터 클래스 등이 어떤 순서로 메시지(예: 가격 계산, 데이터 전송 등)를 주고받는지 시간의 흐름에 따라 나타낸다.</p>
<h2 id="2-gui-테스팅-gui-testing">2. GUI 테스팅 (GUI Testing)</h2>
<p>현대 애플리케이션의 핵심인 그래픽 사용자 인터페이스(GUI)를 테스트하는 것은 매우 중요하면서도 까다로운 작업이다.</p>
<h3 id="1-gui웹-애플리케이션의-3계층-구조">1) GUI(웹) 애플리케이션의 3계층 구조</h3>
<p>총 3개의 계층으로 구성되고, 각각 프레젠테이션 계층, 애플리케이션 계층, 데이터 계층으로 나뉜다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/2e7b9827-5409-49ee-a1f1-a0601cd19cca/image.png" alt=""></p>
<ul>
<li>프레젠테이션 계층 (Front-end): HTML5, JavaScript, CSS로 구성되며, 사용자에게 직접 보여지는 인터페이스를 관리한다.</li>
<li>애플리케이션 계층 (Back-end): Java, .NET, Python 등으로 구현되며, 프론트엔드의 요청에 응답하여 실제 고객의 요청을 처리하는 비즈니스 로직을 담당한다.</li>
<li>데이터 계층 (Data Layer): MySQL, Oracle 등 데이터베이스 및 파일 서버를 통해 안정적인 데이터 관리를 수행한다.
.<h3 id="2-gui-테스팅의-본질적인-한계와-이슈">2) GUI 테스팅의 본질적인 한계와 이슈</h3>
단순한 명령줄(CLI) 기반 시스템과 달리 조작 경우의 수가 기하급수적으로 많아진다. 예를 들어 마이크로소프트 워드패드 같은 소형 프로그램조차 325개의 GUI 조작 경우의 수가 존재한다.</li>
</ul>
<p>특정 기능을 수행하기 위해 <strong>이벤트의 연속성(Sequence of GUI events)</strong> 이 필요하다. 예를 들어 파일을 열려면 &#39;파일 메뉴 클릭 → 열기 선택 → 대화상자에 파일명 입력 → 새 창으로 포커스 이동&#39;이라는 일련의 과정을 거쳐야 하므로 순서 조합 문제가 폭발적으로 증가한다.</p>
<h3 id="3-gui-테스팅-수행-기법-4가지">3) GUI 테스팅 수행 기법 4가지</h3>
<p>어떻게 테스트 케이스를 만들고 이벤트를 입력하며 결과를 확인할 것인지에 따라 4가지로 나뉜다.</p>
<h4 id="a-수동-테스팅-manual-testing">A. 수동 테스팅 (Manual Testing)</h4>
<p>비즈니스 요구사항 문서에 명시된 내용에 따라 테스터가 직접 마우스와 키보드를 조작하여 화면이 맞게 동작하는지 확인한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/793251a7-b50d-43d8-8307-71aa5ffb4385/image.png" alt=""></p>
<h4 id="b-모델-기반-테스팅-model-based-testing">B. 모델 기반 테스팅 (Model-based Testing)</h4>
<p>시스템의 동작을 그래픽 모델로 변환하여 작동 방식을 예측한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/c0821b44-c8a4-4868-8035-c2908228c886/image.png" alt=""></p>
<p>시스템 요구사항을 바탕으로 효율적인 테스트 케이스를 생성하며, 특히 GUI가 절대 도달해서는 안 되는 &#39;원치 않는 상태(undesirable state)&#39;를 식별해 내는 데 장점을 가진다.</p>
<h4 id="c-레코드-및-리플레이-record--replay">C. 레코드 및 리플레이 (Record &amp; Replay)</h4>
<p>도구가 사용자의 마우스 움직임, 키보드 입력 등의 모든 상호작용을 스크립트로 캡처(기록)해 두었다가, 정확히 동일한 상호작용 세션을 자동으로 재실행(Playback)하는 방식이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/683b6b37-c4ad-42e0-8143-01efde364e5f/image.png" alt=""></p>
<p>OS와 디바이스 드라이버 단의 이벤트를 낚아채어 작동한다.</p>
<h4 id="d-스크립팅-테스팅-scripting-testing">D. 스크립팅 테스팅 (Scripting Testing)</h4>
<p>프로그래밍 언어를 사용하여 테스트 스크립트를 작성한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/01d06fb5-6b5b-41c4-97a0-ac65bf546e24/image.png" alt=""></p>
<p>실행 중 발생하는 인간의 실수를 원천적으로 제거할 수 있으며, 코드를 약간 수정하여 회귀 테스트(Regression Testing)에 지속적으로 재사용할 수 있다.</p>
<hr>
<h2 id="3-주요-자동화-테스팅-도구">3. 주요 자동화 테스팅 도구</h2>
<p>GUI 테스팅을 효율적으로 수행하기 위한 대표적인 자동화 도구들이다.</p>
<h3 id="1-testcomplete">1. TestComplete</h3>
<p>코딩 지식이 없는 팀도 사용하기 좋은 스크립트리스(Scriptless) 레코드 및 리플레이 도구다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e65940f2-23a5-4147-bb99-575238a06de5/image.png" alt=""></p>
<p>데스크톱, 모바일, 웹 환경을 모두 지원하며, AI 기반 객체 인식 엔진을 탑재하여 스마트한 테스트 보고서를 제공하는 것이 특징이다.</p>
<h3 id="2-selenium-셀레늄">2. Selenium (셀레늄)</h3>
<p>웹 애플리케이션 검증에 가장 널리 쓰이는 무료 오픈소스 프레임워크이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/f5477572-7fff-4283-9e60-10a1302ecc49/image.png" alt=""></p>
<p>Java, Python, C# 등 다양한 프로그래밍 언어로 스크립트를 짤 수 있으며, WebDriver API를 사용하여 브라우저의 동작을 훨씬 더 현대적이고 안정적인 방식으로 자동 제어한다.</p>
<h3 id="3-guitar">3. GUITAR</h3>
<p><strong>네이버(Naver)에서 제공하는 GUI 기반의 테스트 자동화 프레임워크</strong>이며, 사용자의 작업 정보로 생성된 테스트 스크립트를 직접 또는 원격으로 실행(Agent 활용)하여 반복적인 테스트를 수행한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/abe57e35-2177-4045-a2c1-75638ee0b8a0/image.png" alt=""></p>
<p>테스트 시나리오를 한국어로 작성할 수 있다는 편의성이 있고, 로그인과 같이 여러 ID와 비밀번호 입력이 반복적으로 요구되는 시나리오를 효과적으로 자동화할 수 있다.</p>
<h3 id="4-apache-maven-마븐">4. Apache Maven (마븐)</h3>
<p>Java 프로젝트의 빌드(Build) 및 외부 라이브러리 의존성(Dependency)을 관리하는 핵심 도구이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/13a0e67d-5b84-4a7c-bf6a-982e59a83612/image.png" alt=""></p>
<p>프로젝트의 구조와 라이브러리를 표준화하여 관리하며, 설정에는 XML 기반의 <code>pom.xml</code> 파일을 사용한다.</p>
<h3 id="5-그-외">5. 그 외</h3>
<p>크로스 플랫폼 테스팅을 위한 OpenText Functional Testing (VBScript 사용)과 IBM DevOps Test UI 등이 존재한다.</p>
<h2 id="4-cicd-기반-ui-테스트-자동화-selenium--junit--maven">4. CI/CD 기반 UI 테스트 자동화 (Selenium + JUnit + Maven)</h2>
<p>코드 작성 $\rightarrow$ 빌드 $\rightarrow$ 테스트 $\rightarrow$ 배포로 이어지는 전체 과정을 자동화하는 <strong>CI/CD (Continuous Integration/Continuous Delivery)</strong> 연계 전략이다.</p>
<p>프론트엔드부터 백엔드까지 각 자동화 도구는 다음과 같이 역할을 분담하여 파이프라인을 구성한다.</p>
<ul>
<li><strong>Maven:</strong> 전체적인 의존성 관리, 빌드(<code>Maven Build</code>) 수행, 테스트 실행 과정을 통제한다.</li>
<li><strong>JUnit:</strong> 자바 기반 테스트 프레임워크로서, <code>JUnit Test</code> 단계에서 Assert문을 활용해 결과의 성공/실패를 검증한다.</li>
<li><strong>Selenium WebDriver:</strong> 웹 브라우저를 자동으로 제어하여 사용자의 동작을 모방하는 <code>Selenium UI Test</code>를 수행한다.</li>
</ul>
<p>개발자가 코드를 커밋(<code>Code Commit</code>)하면 빌드와 단위 테스트, UI 테스트가 순차적으로 자동 실행되며, 이 결과를 바탕으로 최종 배포 여부를 결정하게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW Engineering & Testing (11) - Test Driven Development & JUnit]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-11-Test-Driven-Development-JUnit</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-11-Test-Driven-Development-JUnit</guid>
            <pubDate>Tue, 19 May 2026 12:56:04 GMT</pubDate>
            <description><![CDATA[<h2 id="1-other-sw-testing-techniques">1. Other SW Testing Techniques</h2>
<p>TDD 외에도 5가지의 소프트웨어 테스팅 기법에 대해서 존재한다.
(이쪽이 시험에 잘 나온다고 말씀하심)</p>
<h3 id="1-random-testing무작위-테스팅">1) Random Testing(무작위 테스팅)</h3>
<p>명세서(Specifications) 없이 <strong>무작위로 독립적인 입력값을 생성하여 수행하는 블랙박스 테스팅 기법</strong>으로, 주로 예외(Exceptions)가 발생하는지 확인하는 데 사용된다.</p>
<h3 id="2-mutation-testing돌연변이-테스팅">2) Mutation Testing(돌연변이 테스팅)</h3>
<p>새로운 소프트웨어 테스트를 설계하거나 기존 테스트 스위트(Test Suites)의 품질을 평가하기 위해 사용된다. <strong>의도적으로 결함을 삽입한 &#39;돌연변이(Mutant)&#39;를 기존 테스트가 얼마나 잘 탐지하는지(탐지율)를 측정하는 방식으로 테스팅</strong>을 진행하며, 이 때 &#39;돌연변이(Mutant)&#39;는 주로 구문 삭제/복제, 불리언 식 변경, 산술/관계 연산자 변경, 동일 범위 내 변수 교체 등의 &#39;돌연변이 연산자&#39;를 사용한다.
.</p>
<h3 id="3-concolic-testing콘콜릭-테스팅">3) Concolic Testing(콘콜릭 테스팅)</h3>
<p>구체적 실행과 심볼릭(Symbolic) 실행을 결합한 의미로 기존 <strong>무작위 테스팅의 한계를 극복하기 위한 화이트박스 테스팅 기법</strong>이다. 코드 커버리지를 극대화할 목적으로 심볼릭 실행과 정리 증명기(Theorem prover)를 사용하여 Uncovered path를 찾고 테스트 입력값을 자동으로 생성한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/df7d38ab-507b-40b0-b20c-d26a660d3cf0/image.png" alt=""></p>
<h3 id="4-regression-testing회귀-테스팅">4) Regression Testing(회귀 테스팅)</h3>
<p>패치, 기능 향상, 환경 설정 변경 등이 발생한 후 새로운 버그가 나타나지 않았는지 확인하는 테스트이다. 이 테스팅 기법은 전제가 존재하는데, <strong>변경 사항이 이전에 잘 동작하던 코드에 새로운 결함을 도입하지 않았음을 보장</strong>해야 한다.</p>
<h3 id="5-conformance-testing적합성-테스팅">5) Conformance Testing(적합성 테스팅)</h3>
<p>제품이나 시스템이 규정된 요구사항 명세, 계약 또는 규제를 제대로 준수하고 있는지 판단하는 테스트이다.</p>
<h2 id="2-test-driven-developmenttdd">2. Test-Driven Development(TDD)</h2>
<h3 id="1-background">1) Background</h3>
<p>보통 <strong>프로그래머들은 테스트를 지루한 작업으로 여기거나 다른 부서의 역할로 미루는 경향</strong>이 있다. 개발하는 것에 의미를 크게 두고 Product를 만들고 나면 유지보수에 소홀하기 쉽다. 그러다보니 여러번 테스트를 반복할수록 꼼꼼함이 떨어지는 상황이 빈번히 발생한다.</p>
<p>이러한 상황을 해결하기 위해 등장한 방법론이 <strong>TDD 방법론</strong>이다.</p>
<h3 id="2-tddtest-driven-development란">2) TDD(Test-Driven Development)란?</h3>
<blockquote>
<p><strong>코드를 작성하기 전에 테스트 코드를 먼저 작성하고, 이 테스트를 통과하는 것</strong>을 개발의 핵심 원동력으로 삼아 <strong><em>테스트와 코드 개발을 교차(Inter-leave)로 진행</em></strong>하는 개발 방식.</p>
</blockquote>
<p>TDD는 도구의 지원을 받아 개발자가 코드 변경 시마다 반복 가능한 테스트를 유지하고 선택적으로 실행할 수 있도록 장려하기 위해 등장했다. 엄밀히는 애자일 방법론인 익스트림 프로그래밍(XP)의 일부로 도입되었지만, 계획 주도 개발 프로세스에서도 활용할 수 있다.</p>
<h3 id="3-process">3) Process</h3>
<p>TDD는 아래의 프로세스를 거친다. 일종의 사이클을 가지고 테스트를 수행하고 <strong>테스트가 실패하면 해당 기능을 지속적으로 빌드업하고 이후 테스트가 실행 완료될 경우 다음 기능 구현으로 넘어가는 방식</strong>으로 진행된다. 일련의 절차는 아래와 같다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/550c4517-7f56-431e-a4d3-2e109944cbbc/image.png" alt=""></p>
<ol>
<li>몇 줄의 코드로 구현할 수 있는 <strong>작은 기능 단위(Increment)를 식별</strong>한다.</li>
<li>해당 기능을 위한 <strong>자동화된 테스트를 작성</strong>한다.</li>
<li><strong>모든 테스트를 실행. 아직 실제 코드가 없으므로 새로운 테스트는 실패한다.</strong></li>
<li>테스트를 통과하기 위한 <strong>실제 기능 코드를 작성</strong>한다.</li>
<li>다시 테스트를 실행하여 <strong>모든 테스트가 성공하면 다음 기능 구현</strong>으로 넘어간다.</li>
</ol>
<h3 id="4-benefit">4) Benefit</h3>
<p>TDD는 좋은 테스팅 기법이다. 고로 여러 장점을 가지는데 아래의 4가지의 장점을 중심으로 생각해볼 수 있다.</p>
<p><strong>1) 코드 커버리지</strong>
작성된 모든 코드는 최소 하나 이상의 연관된 테스트를 가지게 된다는 의미이다. 
<strong>2) 회귀 테스트가 진행</strong>
프로그램이 개발됨에 따라 회귀 테스트 스위트가 점진적으로 구축되어 변경으로 인한 오류를 방지한다. 
<strong>3) 디버깅 간소화</strong>
만약 테스트를 실패한다하더라도, 직전에 작성한 새로 추가된 코드에 문제가 있음이 명확하므로 디버깅이 간단하다. 
<strong>4) 시스템 문서화의 역할을 수행</strong>
작성된 테스트 자체가 코드가 무엇을 해야하는지 설명하는 일종의 Document(문서)의 역할을 수행한다.</p>
<h3 id="5-apply">5) Apply</h3>
<p>TDD는 <strong>테스트 케이스를 언제 만들 것인지에 따라</strong> &#39;기존 개발 방법(전체 개발 후 전체 테스트)&#39;, &#39;모듈별 테스트&#39;, &#39;모듈별 TDD&#39;, &#39;전체 TDD&#39; 등 <strong>다양한 전략으로 접근</strong>할 수 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/7b91a6b2-1b3e-4cc7-a767-f8d814173924/image.png" alt=""></p>
<h2 id="3-junit의-개념-및-활용">3. JUnit의 개념 및 활용</h2>
<h3 id="1-introduction">1) Introduction</h3>
<p>켄트 벡(Kent Beck)이 90년대 중반 Smalltalk용으로 개발한 xUnit을 바탕으로, 켄트 벡과 에릭 감마가 비행기 안에서 공동 개발한 자바 TDD의 표준 도구이다. JUnit은 기존 프로그램을 건드리지 않고 테스트 수행이 가능하며 사용자가 결과값을 일일이 눈으로 확인하지 않아도 된다. xUnit 툴은 어떤 언어를 사용하느냐에 따라 다양한 방식으로 개발될 수 있다.</p>
<h3 id="2-o-o-program">2) O-O Program</h3>
<p>void main() 함수는 프로그램 수행의 시작 함수로 Java Application은 main() 내부에서 모든 제어를 담당한다. O-O program은 기존 프로그램을 건드리지 않고 테스트 수행이 가능하다. 또한 사용자가 결과값을 확인하지 않아도 된다.</p>
<p>아래와 같은 방식으로 Test Case를 수행한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/418e8823-87e4-4621-b535-8081528de24a/image.png" alt=""></p>
<p>테스트는 Precondition(사전 조건) 설정 ➔ 해당 코드 수행 ➔ 결과값 확인(Assert)의 흐름으로 진행된다. 결과를 검증하기 위해 assertEquals, assertFalse, assertTrue, Assert(Not)Null, Assert(Not)Same 등 다양한 Assert 메서드를 제공한다.</p>
<h3 id="3-eclipse-연동하기">3) Eclipse 연동하기</h3>
<p>그럼 Eclipse로 실습을 해보자.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/b9396581-a315-41f2-b56a-24f06418151c/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/425aa788-c9fb-4393-b519-b03c00b5f327/image.png" alt=""></th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/ca3b4768-5981-4b20-9c05-a8a144644cd2/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/87b66e60-25f0-40d5-b000-ce49363f8d31/image.png" alt=""></th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/a708108e-ea82-4b25-bfed-d2698b3341a0/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/05eb5712-8224-4d98-b5b3-d6927c52f657/image.png" alt=""></th>
</tr>
</thead>
</table>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/91b48253-ee43-4db0-8e29-d5d75479415e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/c1c66101-ce75-4ba0-9440-75e0cd7670ed/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/23022379-025a-4cf2-8351-03c059c8bbbb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/a935c23d-ef9f-4d8b-aa3f-6fd266851a65/image.png" alt=""></p>
<p>Eclipse에서 프로젝트를 생성할 때 테스트 클래스는 반드시 일반 클래스가 아닌 <strong>&quot;JUnit Test Case&quot;</strong> 형태로 만들어야 한다. 또한 org.junit.Assert.* 및 org.junit.Test를 올바르게 import 하는 것을 반드시 기억해야한다.</p>
<p>실행 결과는 녹색 막대(성공) 또는 붉은 막대(실패)로 직관적으로 표시된다.</p>
<h3 id="fixture">Fixture</h3>
<p><strong>@Before</strong> 어노테이션을 사용하여 <strong>각 테스트 전에 필요한 객체를 초기화(setUp)</strong> 하고, <strong>@After</strong>를 사용하여 테스트 종료 후 <strong>자원을 정리(tearDown)하는 일관된 테스트 환경을 구성</strong>할 수 있다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/4a997c3e-a31c-4eef-af50-9592cbb1a96c/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/e463d3b9-8332-421a-9062-0c8229af493b/image.png" alt=""></th>
</tr>
</thead>
</table>
<h3 id="timeout--ignore">Timeout &amp; @Ignore</h3>
<p>특정 시간 내에 로직이 수행되는지 검사하려면 @Test(timeout=130)과 같이 시간을 지정하고, 실행을 잠시 보류하려면 @Ignore를 사용한다. 만약 예상되는 예외를 검증하려면 @Test(expected=Exception)을 사용한다.</p>
<h3 id="junit-annotation">JUnit Annotation</h3>
<p>JUnit과 관련된 Annotation을 정리해보면 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/33fe49c5-55c4-4467-a1ef-9786daae890c/image.png" alt=""></p>
<h3 id="junit-4-vs-junit-5">JUnit 4 vs JUnit 5</h3>
<p>JUnit 4에서 JUnit 5로 넘어가며 어노테이션 이름이 변경되었습니다. <strong>@Before는 @BeforeEach</strong>로, <strong>@After는 @AfterEach</strong>로, 전체 수행용인 <strong>@BeforeClass/@AfterClass는 @BeforeAll/@AfterAll</strong>로, 비활성화를 뜻하는 <strong>@Ignore는 @Disabled</strong>로 명칭이 바뀌었다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/3be5f83a-98a8-4c0c-b280-a9f83efe2745/image.png" alt=""></p>
<h3 id="junit-vs-testng">JUnit vs TestNG</h3>
<p>JUnit은 주로 <strong>단위 테스트에 초점이 맞춰져 있고 병렬 실행이나 그룹화에 제한</strong>적인 반면 TestNG는 <strong>단위, 통합, 대규모 테스트를 모두 아우르며</strong> 병렬 실행, 강력한 그룹화, XML 설정, 데이터 기반 테스트 등 <strong>훨씬 강력한 부가 기능을 제공</strong>한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/d4cc431e-d179-4c2c-92dd-7e352ada298a/image.png" alt=""></p>
<h2 id="4-단위-테스팅unit-testing-실습">4. 단위 테스팅(Unit Testing) 실습</h2>
<p>EclEmma (자바 Coverage 도구): Eclipse Marketplace에서 설치 가능하며, Coverage As ➔ JUnit Test 모드로 테스트를 실행하면 내가 작성한 테스트 코드가 실제 프로덕션 코드의 몇 퍼센트를 실행(커버)했는지 시각적으로 확인할 수 있습니다
.
GTest (Google Test): Visual Studio 환경에서 C++ 코드를 테스트할 때 사용하는 유닛 테스트 라이브러리입니다
. TEST(TestCaseName, TestName) 형식의 매크로로 테스트를 정의하고, 값을 비교할 때 EXPECT_EQ, EXPECT_TRUE 등의 매크로를 사용합니다
.
Triangle Problem 실습: TDD의 구체적 사례로, 세 변의 길이를 입력받아 정삼각형(Equilateral), 이등변삼각형(Isosceles), 일반 삼각형(Scalene), 삼각형 아님(NotTriangle), 입력 오류(InputValidation)를 판별하는 프로그램을 작성합니다
. 점진적으로 실패하는 테스트 코드를 먼저 만들고 코드를 구현해나가는 과정이 GTest 코드로 상세히 예시되어 있습니다
.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW Engineering & Testing (10) - Structural Testing]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-10-Structural-Testing</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-10-Structural-Testing</guid>
            <pubDate>Mon, 18 May 2026 09:08:42 GMT</pubDate>
            <description><![CDATA[<h1 id="path-based-testing">Path-based Testing</h1>
<h2 id="introduction">Introduction</h2>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e6a3f17b-3598-4900-9225-97e651df0d62/image.png" alt=""></p>
<h2 id="structural-programming">Structural Programming</h2>
<h3 id="introduction-1">Introduction</h3>
<p>구조적 프로그래밍 기법은 단순성을 지향한다. 복잡한 코드도 Sequence(순차), Selection(선택), Repetition(반복)이라는 3가지 기본 구조만으로 표현할 수 있다. </p>
<p>구조적 프로그램 생성 규칙은 아래와 같다.</p>
<ol>
<li>가장 단순한 형태에서 시작하라.</li>
<li>어떤 작업 상태든 연속된 두 개의 작업 상태로 대체할 수 있다.</li>
<li>어떤 작업 상태든 임의의 제어 구문으로 대체할 수 있다.</li>
<li>규칙2와 규칙3은 원하는 만큼, 어떤 순서로든 자유롭게 적용할 수 있다.<h3 id="프로그램-구조">프로그램 구조</h3>
<img src="https://velog.velcdn.com/images/woong_crouch/post/88162136-26c3-45fc-b887-6898840b8bca/image.png" alt="">
규칙 적용의 예시는 아래와 같다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/1118bc93-80fc-4ebb-b3e2-5136c9b4dc8b/image.png" alt=""> | <img src="https://velog.velcdn.com/images/woong_crouch/post/51f04ed6-29ff-4c29-a466-8bb4e64f373b/image.png" alt=""> --|--|</p>
<h3 id="cfgcontrol-flow-graph">CFG(Control Flow Graph)</h3>
<p>구조적 테스트를 수행하려면 먼저 코드의 실행 흐름을 시각적으로 모델링해야 하며, 이를 위해 CFG를 작성한다.
CFG는 아래의 몇가지 구성요소를 가진다.</p>
<ul>
<li>노드(Nodes): 분기(Branch) 없이 순차적으로 실행되는 구문 또는 구문들의 연속인 &#39;기본 블록(Basic Block)&#39;을 의미한다.</li>
<li>기본 블록(Basic Block): 첫번째 구문이 실행되면 블록 내의 모든 구문이 반드시 실행된다.</li>
<li>간선(Edges): 제어 흐름을 나타낸다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/a0fc19c4-8e7a-431f-a745-88c93d83bf9c/image.png" alt="">
<img src="https://velog.velcdn.com/images/woong_crouch/post/56e3a3df-2650-4b34-9894-e71e72b58ef1/image.png" alt="">
<img src="https://velog.velcdn.com/images/woong_crouch/post/d6bf5fc8-caa5-4c12-a2c0-b5007c948166/image.png" alt="">
<img src="https://velog.velcdn.com/images/woong_crouch/post/499bddf2-1024-42f4-8083-f60a14e88e7d/image.png" alt="">
<img src="https://velog.velcdn.com/images/woong_crouch/post/fb561903-4eb9-4c28-97aa-4071de4da9f2/image.png" alt="">
<img src="https://velog.velcdn.com/images/woong_crouch/post/c1f817de-2754-4a1c-aacd-512033422255/image.png" alt="">
<img src="https://velog.velcdn.com/images/woong_crouch/post/bd1579cf-553c-426a-a5fc-2417f13814e2/image.png" alt=""></li>
</ul>
<p>CFG를 작성할 때는 몇 가지 주의사항이 있다. 우선 if-return 구문을 작성할 때, if문 안과 밖에 모두 return이 있는 경우 두 return 노드는 반드시 별개의 노드로 구분되어야한다. 또한 while &amp; for 구문에서 loop가 시작되기 전에 loop 변수를 초기화하는 dummy node가 암묵적으로 생성됨을 고려해 그려야한다.</p>
<h2 id="test-coverage">Test Coverage</h2>
<p>CFG를 작성한 이후에는 어떤 경로로 테스트를할 것인가를 &quot;기준(Criteria)&quot;으로 정립해야한다. 이 기준의 엄격함에 따라 다양한 커버리지로 분류된다.</p>
<h3 id="statement-coverage">Statement Coverage</h3>
<p>프로그램 내의 모든 구문이 최소  한 번 이상 실행되도록 보장하는 가장 기본적인 커버리지이다. 반복문을 통해 입력값을 더하고 -1이 입력되면 종료 후 평균을 계산하는 프로그램이 있다고 가정하였을 때, 정상적으로 값이 입력되는 경로와 조건문들이 실행되는 경로를 포함하는 테스트 패스가 2개면 모든 노드(구문)을 방문하는 것이다.</p>
<h3 id="decisionbranch-coverage">Decision(Branch) Coverage</h3>
<p>프로그램의 모든 진입점과 진출점이 최소 한 번 이상 호출되며, 프로그램 내의 모든 결정이 True &amp; False의 결과를 최소 한 번 이상 가져야 한다. CFG 상의 모든 간선(Edge)을 순회하는 것과 같다.</p>
<h3 id="conditiondecision-coveragecdc">Condition/Decision Coverage(C/DC)</h3>
<p>결정 커버리지를 만족하는 동시에, 결정 구문 내부를 구성하는 각각의 개별 &#39;조건(Condition)&#39;들도 모두 참과 거짓을 최소 한 번씩 가지는 것을 말한다. </p>
<p>예시로 A||B의 경우 결정 자체도 true/false가 나와야 하고, A와 B도 각각 true/false가 나와야하므로 최소 테스트 셋은 (True, True)와 (False, False)가 된다.</p>
<h3 id="modified-conditiondecision-coveragemcdc">Modified Condition/Decision Coverage(MC/DC)</h3>
<p>가장 엄격한 기준으로, 각각의 개별 조건이 전체 결정의 결과에 <strong>&#39;독립적으로 영향을 미친다(independently affect)&#39;</strong> 는 것을 증명해야 한다. 이를 증명하려면 특정 조건의 값만 변경하고 나머지 조건들은 고정(holding fixed)했을 때, 전체 결과가 달라지는 것을 보여줘야 한다.</p>
<h4 id="excemple---mcdc">Excemple - (MC/DC)</h4>
<ul>
<li><p><strong>AND 연산 (A &amp;&amp; B)</strong>
A의 독립성을 증명하기 위해선 B를 True로 고정하고 A를 T/F로 변경한다. 즉, (T,T)와 (F,T)가 필요하다. 반대로, B의 독립성을 증명할 때엔 A를 True로 고정하고 B를 T/F로 변경한다. 즉, (T,T)와 (T,F)가 필요하다. 결과적으로 최소 테스트 셋은 <strong>{(T,T), (T,F), (F,T)}</strong> 가 됩니다</p>
</li>
<li><p><strong>OR 연산 (A || B)</strong>
AND와 동일한 원리로 전체가 거짓이 되는 (F,F)를 기준으로 각 변수를 하나씩 True로 바꾼 <strong>{(T,F), (F,T), (F,F)}</strong> 가 최소 테스트 셋이 된다.</p>
</li>
<li><p><strong>윤년 계산기(isLeap(int year))</strong> : 윤년 조건 ((year%4 == 0) &amp;&amp; (year%100 != 0)) || (year%400 == 0)을 C1, C2, C3로 나눌 때, 각 조건(Variant)이 전체 결과에 영향을 미치는지 분석(예: B2는 B1의 C1 variant 등)하여 독립성을 증명하는 테스트 패스를 구성해야 한다.</p>
</li>
</ul>
<h2 id="dataflow-testing">Dataflow Testing</h2>
<p>경로 기반 테스팅이 제어의 흐름에 집중했다면, 데이터 흐름 테스팅은 변수의 값이 어디서 정의되고 어디서 사용되는지 그 생명 주기를 추적하여 결함을 찾는다.</p>
<p>Dataflow Testing에는 두 가지 개념이 나오는데, 첫째로 Def는 Definition으로, 값이 메모리 위치에 저장되는 시점을 말한다. formal parameter로 사용되거나 input으로 값을 받을 때와 같은 상황에서 주로 발생한다. 두번째 개념은 Use로, 변수의 값이 접근(사용)되는 시점을 말한다. 대입 연산자의 우측에 올 때, 조건문의 평가에 사용될 때, 반환 및 출력되는 상황 등에서 발생한다.</p>
<h3 id="definition-of-def-use-pair">Definition of Def-Use Pair</h3>
<p>DU Pair는 특정 변수에 대해 (Def, Use)의 쌍을 묶은 것이다. 단, 이 쌍이 성립하려면 값이 정의된 후 사용되기 전까지 <strong>다른 값으로 재정의되지 않는 &#39;Def-clear path&#39;</strong> 여야만 한다.
def와 use가 같은 노드에 나타날 경우, 루프 내에서 정의가 사용 후에 발생하면 DU 쌍이 생성된다. def 사용 전에 발생할 경우, DU pair가 생성되지 않는다. 마지막으로 DU pair는 새로운 중간 정의 없이 정의가 제거된 경로여야 한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e6848e1c-24c5-470c-a90b-9d09101c2637/image.png" alt=""></p>
<h2 id="program-slicing">Program Slicing</h2>
<p>프로그램 슬라이싱은 오류 추적과 프로그램 분석을 극대화하기 위해 코드를 잘라내어 분석하는 기법입니다
.
정적 후방 슬라이스 (Static, Backward Slice) S(V, n): 특정 시점(Slice criterion)에 해당하는 노드 n에서의 변수 집합 V의 값에 영향을 미치는 프로그램 내의 &#39;모든 구문 조각(statement fragments)들의 집합&#39;을 역추적하여 계산하는 방법입니다
.
적용 분야: 오류의 근원을 더 쉽게 찾는 디버깅(Debugging), 소프트웨어 유지보수, 코드 최적화, 프로그램 분석, 정보 흐름 제어 등에 유용하게 사용됩니다
.</p>
<hr>
<ol start="5">
<li>테스트 기법 분석 (효과와 비용 비교)
강의 자료에서는 이러한 구조적 테스팅(Code-based testing) 기법들과 명세 기반 테스팅(Spec-based testing, 예: 경곗값 분석, 동치 분할)을 분석 비용(Effort), 테스트 케이스의 수, 의미적 내용(Semantic content) 측면에서 비교합니다
.
의미적 내용 (Semantic Content): 명세 기반의 Boundary Value(경곗값)나 Path Testing은 의미론적 파악 요구도가 낮은 편입니다
. 반면 구조적 기법인 Slice Testing이나 Data flow testing, 명세 기반의 Decision table 등은 구조 및 로직에 대한 높은 수준의 의미적 이해(High semantic content)를 요구합니다
.
테스트 케이스 식별 노력 (Test case identification effort): Data flow testing이나 Slice testing은 내부 로직을 일일이 추적해야 하므로 분석 노력이 매우 높게(High) 듭니다
. 반면 동치 분할(Equivalence class)이나 경곗값 테스트는 비교적 쉽게 식별(Low effort)할 수 있습니다
.
테스트 케이스의 수 (Number of test cases): 경곗값 테스트(Boundary value testing)와 프로그램 슬라이싱(Slice testing)은 생성되는 테스트 케이스의 수가 굉장히 많아집니다
. 반면 Decision table이나 Basic path testing은 상대적으로 적은 테스트 케이스를 생성합니다
.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW Engineering & Testing (9) - Introduction to SW Testing]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-8-Introduction-to-SW-Testing-504n7m51</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-8-Introduction-to-SW-Testing-504n7m51</guid>
            <pubDate>Sun, 03 May 2026 03:00:51 GMT</pubDate>
            <description><![CDATA[<h1 id="1-test-case-generation-strategy">1. Test Case Generation Strategy</h1>
<p>Test Case(TC)는 Test Input과 정답을 포함해서 사용된다.</p>
<p>소프트웨어 테스트 케이스를 생성하는 전략은 크게 소프트웨어의 내부 구조 참조 여부에 따라 두 가지로 나뉜다. 1) 블랙박스 테스팅과 2) 화이트박스 테스팅이다.</p>
<h2 id="1-black-box-testing">1) Black-Box Testing</h2>
<p>블랙박스 테스팅 (Black-Box Testing)은 프로그램의 내부 구조를 보지 않고 &#39;블랙박스&#39;로 간주하여 테스팅하는 기법이다. 내부를 살피지 않고 기능이 명세서(Specification)에 명시된 요구사항을 충족하는지를 중점적으로 보는 것이다. 이 방법을 사용하면 소스 코드가 완성되기 전, 소프트웨어 프로세스의 초기 단계부터 명세서를 바탕으로 테스트 계획을 시작할 수 있다는 장점이 있다.</p>
<h3 id="equivalence-partitioning">Equivalence Partitioning</h3>
<p>이 때 동치 분할 (Equivalence Partitioning)이라는 개념이 사용되는데, Equivalence Partitioning이란, 입력 데이터와 출력 결과가 동일하게 취급되는 클래스(집합)들로 나뉜다는 원리를 이용하는 것을 말한다. </p>
<p>하나의 파티션(클래스) 내의 모든 입력에 대해 프로그램이 동일하게(동등하게) 동작한다고 가정하므로,<strong>각 클래스에서 모든 값을 테스트할 필요 없이 대표 테스트 케이스만 선택하여 테스트</strong>한다.</p>
<p>10,000~99,999 사이의 5자리 정수가 입력 조건이라면, 범위를 &lt;0-9999&gt;, &lt;10000-99999&gt;, &lt;100000 이상&gt;으로 분할하고 각 경계값인 00000, 09999, 10000, 99999, 100000을 추출하여 테스트하는 것을 예로 들 수 있다.</p>
<h2 id="2-화이트박스-테스팅-white-box-testing">2) 화이트박스 테스팅 (White-Box Testing):</h2>
<p>블랙박스 테스팅과는 상반된 방식으로, 구조적 테스팅(Structural testing)이라고도 불리며 모듈 내부의 실제 소스 코드를 들여다보고 프로그램 구조에 따라 테스트 케이스를 도출한다. 이 방식은 프로그램에 대한 지식을 바탕으로 추가적인 테스트 케이스를 식별해 낸다.</p>
<p>화이트박스 테스팅의 목표는 프로그램의 모든 구문, 조건, 의사결정들을 한 번 이상 실행해보는 것이다. <del>단, 무한할 수 있는 모든 경로의 조합을 실행하는 것은 아니다.</del></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/4bd04339-28b1-4400-8014-32335360cd37/image.png" alt=""></p>
<p>화이트박스 테스팅의 예시로는 이진 탐색이 있다. Java 소스 코드를 분석하여 while 문과 if 조건문들을 거치는 4가지의 독립적인 경로(Independent paths: 1-2-8-9, 1-2-3-8-9 등)를 도출하고, 이를 Program Flow Graph로 모델링하여 검증한다.</p>
<h1 id="2-specification-based-testing">2. Specification-based Testing</h1>
<h2 id="introduction">Introduction</h2>
<p>명세 기반 테스팅은 블랙박스 테스팅 또는 기능 테스팅(Functional testing)이라고도 불린다.</p>
<p>명세 기반 테스팅의 가장 큰 장점은 프로그램 내부의 구현(Implementation) 방식이 변경되더라도 명세가 바뀌지 않는 한 테스트 케이스는 변경되지 않으며, 프로그램 구현과 동시에 테스트 케이스를 병행하여 개발할 수 있다는 것이다.</p>
<p>명세(Specification)와 프로그램, 테스트 케이스의 관계 (벤 다이어그램 시각화) 실제 개발 환경에서 명세(S)와 개발된 프로그램(P)은 완벽히 일치하지 않는다.</p>
<p>위의 그림에서 Scope 1이 명세서에서 기대되고(Expected), 프로그램에 올바르게 구현되었으며(Programmed), 성공적으로 테스트된(Tested) 이상적인 영역이고, Scope 2와 5는 명세서에서 요구하여 기대되지만(Expected), 아직 테스트되지 않은 영역이며 Scope 6은 명세서에 없는데 개발자가 임의로 구현했으며(Programmed, not expected), 테스트되지도 않은 잠재적 결함 영역이다.</p>
<h3 id="ieee-표준-소프트웨어-결함-분류">IEEE 표준 소프트웨어 결함 분류</h3>
<p>IEEE 표준 소프트웨어 결함 분류 (IEEE Std. Fault Types - 1993) 소프트웨어에서 발생하는 이상 징후는 다음과 같이 5가지로 분류된다. </p>
<ul>
<li>입력/출력 결함 (Input/Output Faults): 올바른 입력 거부, 잘못된 입력 수용, 잘못된 포맷, 결과 오류, 타이밍 오류 등</li>
<li>논리 결함 (Logic Faults): 처리 케이스 누락 또는 중복, 극단적 조건 무시, 잘못된 변수 테스트, 조건 누락, 연산자 오류(예: &lt; 대신 &lt;= 사용) 등</li>
<li>계산 결함 (Computation Faults): 알고리즘 오류, 계산 누락, 피연산자/연산 오류, 괄호 에러, 반올림/잘림 등 정밀도 부족</li>
<li>인터페이스 결함 (Interface Faults): 잘못된 인터럽트 처리, I/O 타이밍, 존재하지 않거나 잘못된 프로시저 호출, 파라미터 불일치</li>
<li>데이터 결함 (Data Faults): 초기화 오류, 변수/인덱스/플래그 잘못 사용, 데이터 차원 및 타입 오류, 센서 데이터 한계 초과, Off-by-one(1 차이 연산) 오류 등</li>
</ul>
<h2 id="명세-기반-테스팅의-핵심-기법">명세 기반 테스팅의 핵심 기법</h2>
<h3 id="경계값-테스팅-boundary-value-testing">경계값 테스팅 (Boundary Value Testing)</h3>
<p>입력이나 출력 도메인의 변수 영역 끝부분(경계)에서 오류가 가장 많이 발생한다는 것을 바탕으로하는 테스팅 기법이다.</p>
<h4 id="normal-boundary-value-testing">Normal Boundary Value Testing</h4>
<p>예외를 제외하고 유효한 입력의 경계값만을 독립적으로 다룬다. <strong>&lt;최솟값, 최솟값+1, 정상값, 최댓값-1, 최댓값&gt;</strong> 5가지 포인트를 중심으로 테스트를 수행한다.</p>
<h4 id="robustness-testing">Robustness Testing</h4>
<p>Normal 테스팅의 확장판으로 예외 처리 상황까지 중심으로 테스팅한다. <strong>Normal Boundary Value Testing의 포인트를 중심으로 범위를 벗어나는 &lt;최솟값-1, 최댓값+1&gt;을 추가하여</strong> 총 7가지 포인트를 확인합니다 <del>(예: 엘리베이터의 하중 초과 시 동작 테스트)</del></p>
<h4 id="worst-case-testing">Worst-Case Testing</h4>
<p>변수들이 서로 독립적이지 않고 <strong>변수들 간의 의존성을 고려하여 모든 경계값들의 최악의 조합을 산출하는 방식</strong>이다. <del>(Robust worst-case 방식도 존재)</del></p>
<h3 id="동치-클래스-테스팅-equivalence-class-testing">동치 클래스 테스팅 (Equivalence Class Testing)</h3>
<p>중복된 테스트를 피하면서도(avoid redundancy) 완벽하게 테스트했다는 확신을 얻기 위해 사용하는 테스팅 방법으로, 동치 클래스는 교집합이 없어야 하며, 합치면 전체 도메인이 되어야 한다. 또한 입력 값들은 동일 기능을 수행하기 때문에 대표값만 테스트해도 된다.</p>
<p>Testing 방법에 따라 아래 3가지 방법으로 나눌 수 있다.</p>
<h4 id="1-traditional-equivalence">1) Traditional Equivalence</h4>
<p>유효한 값(Valid) 영역과 유효하지 않은 값(Invalid) 영역을 단순히 나누어 각각에서 값을 추출한다.</p>
<h4 id="2-weakstrong-normal-equivalence">2) Weak/Strong Normal Equivalence</h4>
<p>오직 유효한 <strong>정상 케이스(Normal cases)</strong> 에만 집중한다. 입력 변수들이 완전히 독립적이면 Weak, 서로 연관성/의존성이 있으면 조합을 고려하는 Strong 방식을 쓴다.</p>
<h4 id="3-weakstrong-robust-equivalence">3) Weak/Strong Robust Equivalence</h4>
<p><strong>유효한 입력과 유효하지 않은 예외 입력을 모두 고려(Consider both)</strong> 하는 가장 강력한 방식이다. 독립 여부에 따라 Weak와 Strong으로 구분한다.</p>
<h3 id="의사결정-테이블-기반-테스팅-decision-table-based-testing">의사결정 테이블 기반 테스팅 (Decision Table-based Testing)</h3>
<p>1960년대부터 복잡한 논리 관계를 표현하고 분석하는 데 쓰인 기법이다. 프로그램의 action을 수행하기 위한 다양한 조건(c1, c2, c3...)의 참/거짓 논리 조합을 표 형태로 그리고, 각 수행 조건(규칙)별로 빠짐없이 Test Case를 생성한다.</p>
<h4 id="테스트-노력testing-effort과-기법-선택-가이드라인">테스트 노력(Testing Effort)과 기법 선택 가이드라인</h4>
<p>동일한 문제(Triangle, NextDate 등)를 각 기법으로 테스트할 때 도출되는 테스트 케이스의 개수를 비교해 보면, 모든 예외와 변수 의존성을 조합하는 Robust Worst-case (rob. wc) 방식이 압도적으로 가장 많은 테스트 케이스를 요구합니다</p>
<p>테스트 기법 선택 기준은 <strong>1) 변수가 물리적(아날로그)인지 논리적인지, 2) 변수 간 의존성이 있는지, 3) 단일 결함인지 다중 결함 가정이 필요한지, 4) 예외 처리를 고려해야 하는지 여부</strong>에 따라 적절한 기법(a1~a8)을 선택해야 한다.</p>
<h1 id="3-case-studies">3. Case Studies</h1>
<p>수업 자료에서는 이론을 실제화하기 위해 4가지 구체적인 예제를 다룹니다.</p>
<h3 id="1-보험료율-계산-insurance-premium">1) 보험료율 계산 (Insurance Premium)</h3>
<p><strong>조건</strong>
보험료(Premium) = 기본료 * 나이 가중치(ageMultiplier) - 안전운전 할인(safeDrivingReduction). 나이별로 가중치가 다르고(16세~100세), 벌점(Point)이 커트오프 점수 아래일 때만 할인이 주어진다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/32fd5a74-d6ff-4b36-9a97-b19cb72e3631/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/1705109d-09ca-4196-af34-08217672463c/image.png" alt=""> | <img src="https://velog.velcdn.com/images/woong_crouch/post/d6a19ef4-0b36-4b81-8df4-839d4edfa850/image.png" alt=""> --|--|</p>
<p>나이와 벌점이라는 두 변수의 경계값(Min, Max) 및 유효/비유효 구간을 나누어 도식화한 후, 벌점 커트오프 영역을 고려한 &#39;Worst-Case Testing&#39;과 유효/비유효 구간의 대표값을 뽑아내는 &#39;Weak Robust Equivalence Class&#39; 테스트 케이스 도출 과정을 보여준다.</p>
<h3 id="2-환자-관리-시스템-mhc-pms">2) 환자 관리 시스템 (MHC-PMS)</h3>
<p>&quot;Input을 구성해야한다. 환자 상태, 약품, 경고 무시 여부를 나누고 이를 warning 메세지 여부로 출력한다. 그리고 이 모든 조합을 분석해서 TC를 만든다&quot;
<strong>요구사항</strong>
환자가 특정 약품에 알레르기가 있다면 처방 시 시스템이 경고 메시지를 띄워야 합니다. 의사가 경고를 무시하려면 반드시 무시하는 이유를 입력해야 한다.</p>
<p>이때 입력 조건과 출력 조건은 다음과 같다.</p>
<p><strong>입력 조건</strong>: 알레르기 유무(None, One, Two), 처방 약품(Normal, 1개 알레르기, 다중 알레르기), 경고 무시 여부(No, Yes)</p>
<p><strong>출력</strong>: Warning Message 여부.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/291f6ebd-99fc-46d7-9abb-44632001d3a9/image.png" alt=""></p>
<p>이에 따라 나올 수 있는 모든 조합을 분석하여, 정상 처방 시 메시지가 안 뜨는 TC#1부터, 2가지 알레르기가 있는데 이를 모두 무시하고 처방하여 두 가지 사유를 입력받아야 하는 TC#13까지 총 13개의 구체적인 테스트 케이스를 도출해 낸다.
.</p>
<h3 id="3-삼각형-문제-triangle-problem">3) 삼각형 문제 (Triangle Problem)</h3>
<p><strong>문제 정의</strong>
세 정수 a,b,c를 입력으로 받으며 아래의 조건을 만족해야한다.
• a = b = c 이면, 정삼각형 출력
• a, b, c 중 한 쌍만 같을 때, 이등변삼각형 출력
• 한 쌍도 같지 않을 때, 삼각형 출력
• 두 변의 합이 한 변의 길이보다 작으면, “삼각형 아님”</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/3057a87f-9e81-4d96-9952-97913d016cab/image.png" alt=""></p>
<p>입력 도메인과 출력 도메인은 위와같이 분류할 수 있다.</p>
<h3 id="4-triangle-problem---expension">4) Triangle Problem - Expension</h3>
<p><strong>문제 정의</strong>
세 정수 a,b,c의 길이를 입력으로 받으며 아래의 조건을 만족해야한다.
• C1: 1 &lt;= a &lt;= 200, C2: 1&lt;= b &lt;= 200, C3: 1&lt;= c &lt;= 200
• C4: a &lt; b + c, C5: b &lt; a + c, C6: c &lt; a + b</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/c1c998a2-2e9d-4b17-bc59-9da5eb5f6c80/image.png" alt=""></p>
<p>또한 출력은 다음과 같이 정의한다.
• a = b = c이면, 정삼각형 출력
• a, b, c 중 한 쌍만 같을 때, 이등변삼각형 출력
• 한 쌍도 같지 않을 때, 삼각형 출력
• C4, C5, C6가 만족되지 않으면, “삼각형 아님” 출력</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/2e40fb61-9cd4-4117-9e5a-cf776a4f141b/image.png" alt=""></p>
<p>출력값 기준의 Weak Normal Equivalence Class, Strong Robust Equivalence Class를 작성하고, 입력값 변수 기준의 Weak Robust Equivalence Class 테스트 케이스를 뽑아내는 훈련을 제시한다.</p>
<h3 id="5-다음-날짜-구하기-함수-nextdate-function">5) 다음 날짜 구하기 함수 (NextDate Function)</h3>
<p><strong>문제 정의</strong>
년(18122012), 월(112), 일(1~31)의 세 정수를 입력받아 바로 다음 날짜를 출력하는 함수입니다</p>
<p><strong>테스트 케이스 설계</strong>
Weak Robust 기법을 위해 년/월/일의 단순 유효 범위를 M1, D1, Y1으로 나눕니다</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/14bc8d04-349a-499b-9f3b-424dfe7a437b/image.png" alt=""></p>
<p>Strong Normal 기법을 위해 월(30일인 달, 31일인 달, 2월), 일(128일, 29일, 30일, 31일), 년도(비윤년, 윤년, 세기말 평년 등)를 매우 세부적인 조건(M1M3, D1D4, Y1Y3)으로 치밀하게 클래스를 분할하여 테스트 케이스를 설계하는 전략을 보여줍니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW Engineering & Testing (8) - Introduction to SW Testing]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-8-Introduction-to-SW-Testing</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-8-Introduction-to-SW-Testing</guid>
            <pubDate>Wed, 29 Apr 2026 01:16:38 GMT</pubDate>
            <description><![CDATA[<h2 id="introduction">Introduction</h2>
<h3 id="1-임베디드-소프트웨어의-안전성-문제">1) 임베디드 소프트웨어의 안전성 문제</h3>
<p>임베디드 소프트웨어는 다양한 분야에서 폭넓게 활용되고, 이는 실생활과 매우 밀접한 관계를 가진다. IT와 관련된 제품들은 오류를 발생하면 심각한 결과로 이어질 가능성이 있다.</p>
<p>특히나 의료기기나 자동차와 같이 문제가 발생하면 생명에 직결되는 경우에는 심각한 상황을 연출하게 된다.</p>
<h3 id="2-대표적-실패-사례-의료기기-therac-25">2) 대표적 실패 사례: 의료기기 Therac-25</h3>
<p><strong>Therac-25</strong>는 1976년 캐나다 AECL이 개발한 방사능 치료 기기로, 1982년에 하드웨어 제어 방식에서 소프트웨어 제어 방식으로 시스템을 변경했다. 
<img src="https://velog.velcdn.com/images/woong_crouch/post/2254ceb3-a392-4e8e-a04b-51a6a9d06802/image.png" alt=""></p>
<p>1985년에 첫 의료 사고가 발생한 이후 19개월이라는 긴 시간 동안 6건의 사고가 추가로 발생했으며, 이로 인해 3명이 사망하고 3명이 심각한 장애를 입었다. 이후 2000년 파나마 시티에서는 유사한 원인으로 28명이 방사능에 노출되어 23명이 사망하는 참사가 발생했다.</p>
<p>사고 원인에 대해서 알아보기 위해서는 기기에 대한 속성을 파악할 필요가 있다. 해당 기기는 치료실과 제어실이 분리되어 운영중이었으며 기기는 두 가지 동작 모드를 가졌는데, <strong>X-ray 모드</strong>는 텅스텐 스크린 막을 통과시켜 얕은 종양을 치료하는 약한 방사능 모드이고, <strong>Electron 모드</strong>는 피부 깊숙한 종양 치료에 쓰이는 모드이다.</p>
<p>사고 시나리오를 살펴보면 오퍼레이터가 실수로 X-ray 모드를 설정했다가 이를 인지하고 급하게 Electron 모드로 변경하여 치료를 시작했을 때, 기기 내에 <strong>X-ray 모드 수준의 강력한 방사능이 세팅된 상태로 환자에게 그대로 노출</strong>되어 버리는 심각한 결함이 있었습니다</p>
<p>사고 이후에 조사에 따르면, 단 한 명의 프로그래머가 제어 소프트웨어를 작성했으며 개발 완료 후 어떠한 소프트웨어 검증 절차도 거치지 않았다고한다. 그리고 최초 사고 후 여러차례 검증하였으나 원인을 찾지 못했고 이를 통해 임베디드 소프트웨어의 오류는 재현이 어렵다는 것을 확인할 수 있다. 결론적으로 원인을 찾지 못하고 <strong>19개월간 시스템을 그대로 사용</strong>하게 됩니다.</p>
<p>이 사고를 통해 얻을 수 있는 주안점은, 임베디드 소프트웨어는 <strong>엄격한 기능 안전 표준(Functional Safety Standards)</strong>을 바탕으로 철저한 신뢰성 및 안전성 검증을 반드시 거쳐야 한다는 것**이다.</p>
<h2 id="software-testing">Software Testing</h2>
<h3 id="1-왜-소프트웨어를-테스트해야-하는가">1) 왜 소프트웨어를 테스트해야 하는가?</h3>
<p>소프트웨어 테스팅은 시스템에 대해 다음과 같은 가장 중요한 5가지 질문을 던지고 답을 구하는 과정이다.</p>
<ul>
<li>제대로 작동할 것인가? (Will it work properly?)</li>
<li>신뢰할 수 있을 것인가? (Will it be reliable?)</li>
<li>구축하기 쉬울 것인가? (Will it to be easy to build?)</li>
<li>고품질의 설계인가? (Is it a quality design?)</li>
<li>유지보수하기 쉬울 것인가? (Will it be easy to maintain?)</li>
<li>구현과 테스팅의 비중: 프로젝트의 규모(Lines of Code)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/13377c84-e16c-4842-a05b-1ef82305c264/image.png" alt=""></p>
<p>위의 질문들이 커질수록 전체 시간에서 구현과 개발자 테스트가 차지하는 비중은 줄어들게 되지만, 역설적으로 전체 프로젝트 오류 중 소스 코드 구현 시 발생하는 오류의 비중이 가장 높기에 체계적인 테스트를 진행해야한다.</p>
<h3 id="2-소스-코드-검증-기법">2) 소스 코드 검증 기법</h3>
<p>소스 코드 검증 기법은 저번 포스트에서 언급한대로 총 두가지의 방향으로 나뉜다. </p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/d36a025e-6d8c-426b-aded-21bf36a8c89b/image.png" alt=""></p>
<p>우선 <strong>1) 정적 분석(Static Analysis)는 코드를 실행하지 않고 인스펙션을 통해 오류를 사전에 예방</strong>하는 기법이다. 다음으로 <strong>2) 동적 분석(Dynamic Analysis)로 불리는 실제 소프트웨어 소스 코드를 실행하여 오류를 발견</strong>하는 기법이 존재한다.</p>
<h3 id="2-dynamic-testing">2) Dynamic Testing</h3>
<p>Dynamic Testing에는 아래의 4가지 개념이 존재한다.</p>
<ul>
<li><strong>Test data</strong>: 시스템을 테스트하기 위해 의도적으로 고안된 인위적인 입력값.</li>
<li><strong>Test cases</strong>: 시스템에 주어지는 입력값과, 명세서에 따라 시스템이 올바르게 작동할 때 예측되는 &#39;예상 결과값&#39;의 쌍.</li>
<li><strong>Test suite</strong> : 프로그램 테스트에 사용하기 위해 모아둔 테스트 케이스들의 집합.</li>
<li><strong>Test oracle</strong> : 테스트가 통과했는지 실패했는지를 판별할 수 있게 해주는 기준점 메커니즘. (예: 명세서, 문서 등)</li>
</ul>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/d52a42bf-5adf-4b34-87b8-b48685e894d6/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/324f005c-65fa-491e-89b0-00f0d0d5d0e5/image.png" alt=""></th>
</tr>
</thead>
</table>
<p><strong>테스팅은</strong> 프로그램에 오류나 결함이 &#39;존재함&#39;을 밝혀낼 수는 있지만, <strong>결함이 전혀 없음을 증명할 수는 없다.</strong></p>
<p>수많은 테스팅 기법이 존재하지만, 단일 방법 하나만으로 평균 75% 이상의 오류 감지율을 보이는 것은 없고, 오류 감지율을 극대화하려면 V-모델과 같은 생명주기에 맞추어 반드시 <strong>다양한 검증 기법을 병행</strong>해야 한다.</p>
<h2 id="program-testing-technique">Program Testing Technique</h2>
<h3 id="1-program-testing">1) Program Testing</h3>
<p>프로그램 테스트는 <strong>프로그램이 의도대로 작동하는지 확인하고 사용하기 전에 결함을 발견하기위해 진행</strong>된다. 데이터를 만들어서 프로그램을 실행하며, 실행 결과를 검토해 프로그램의 문제를 파악한다. 이 때, 테스트를 통해서는 존재의 여부를 알 수 있지만 오류가 없다는 것을 보장하지는 않는다는 것을 유의해야한다.</p>
<h3 id="2-verification검증과-validation확인">2) Verification(검증)과 Validation(확인)</h3>
<p>Program을 테스팅을 할 때 우리는 두가지 용어를 주의깊게 살필 필요가 있다. </p>
<p><strong>1) Verification(검증)은 &quot;우리가 제품을 올바르게 만들고 있는가?&quot;</strong> 에 대한 질문으로 소프트웨어가 설계 명세서를 정확히 준수하는지를 확인하는 것을 말하고 <strong>2) Validation(확인)은 &quot;우리가 올바른 제품을 만들고 있는가?&quot;</strong> 에 대한 질문으로 소프트웨어가 사용자가 실제로 요구하는 바를 잘 수행하는지를 확인하는 역할을 맡게된다.</p>
<p>그리고 Program testing에는 목적이 두가지 존재하는데, </p>
<p>첫째로 <strong>Validation testing(확인 테스팅)</strong>은 개발자와 고객에게 소프트웨어가 요구사항을 충족한다는 것을 증명하기 위해 사용하며 정상적인 시스템 사용 환경을 반영한 테스트 케이스를 사용한다.
둘째로 <strong>Defect testing(결함 테스팅)</strong>은 시스템이 부정확하거나 명세를 위반하는 상황을 의도적으로 찾아내기 위해 사용하며 사용자가 평소에 사용하지 않는 모호하거나 극단적인 테스트 케이스를 고의로 주입하여 결함을 노출시킵니다</p>
<p>그 중 하나인 Input-Output 모델은 다음과 같은 형태로 동작한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/f00a8388-4b92-473a-a423-394fe4e1b1f4/image.png" alt=""></p>
<h3 id="3-인스펙션정적-분석과-테스팅동적-분석">3) 인스펙션(정적 분석)과 테스팅(동적 분석)</h3>
<p><strong>Inspections(인스펙션)은 정적 분석이라고도 불리며, 시스템의 정적인 결과물(Code, Doc 등)을 분석해 문제를 발견하는 정적인 검증 기법</strong>이다. 근본적으로 코드 실행을 하지 않고 그 전 단계에서 오류를 사전에 예방하고자하는 목적으로 사용한다.</p>
<p><strong>Testing(테스팅)은 동적 분석이라고도 하며, 테스트 데이터를 주입해 시스템을 작동시키고 동작을 관찰하는 동적 검증 기법</strong>이다. 인스펙션과 달리 코드를 실제로 실행시키고 이를 통해 오류를 발견하는 것에 초점을 두고 있다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/26f2ea8f-c271-4f59-81a1-b1f3ea5f3095/image.png" alt=""></p>
<h4 id="advantage-of-inspections">Advantage of Inspections</h4>
<p>인스펙션은 3가지의 장점을 가진다. </p>
<p>첫째로 <strong>오류 간섭(Masking) 회피</strong>이다. <strong>&#39;오류 간섭&#39;이란 테스팅 과정에서 하나의 오류가 다른 오류를 숨기는 현상이 발생하는 것을 말한다.</strong> 테스팅이 가지는 치명적인 단점이 인스펙션에서는 독립적으로 결함을 찾을 수 있어 이를 회피할 수 있다. </p>
<p>둘째로 <strong>비용의 효율성</strong>이다. 시스템이 불완전할 때 테스팅을 하려면 특수한 Test Harnesses를 개발하여 사용 가능 부분을 실행해야하므로 추가 비용이 발생한다. 인스펙션은 <strong>문서 기반이므로 미완성인 코드에 대해 검사를 진행해도 비용을 추가로 지불할 필요가 없다.</strong> </p>
<p>마지막으로 <strong>광범위한 품질 속성 평가</strong>이다. 인스펙션은 버그를 찾는 것 뿐아니라 <strong>프로그램 전반의 품질에 대한 속성들을 종합적으로 평가</strong>하기에 용이하다.</p>
<h4 id="inspection과-testing">Inspection과 Testing</h4>
<p>시스템의 Performance나 사용성(Usability) 같은 시스템 작동 시 발생하는 비기능적 특징은 인스펙션으로 확인할 수 없고 오직 동적 시스템 실행(Testing)을 통해서만 점검할 수 있다. 고로 어느 한가지 기법만을 이용하는 것이 아닌 *<em>두 기법을 병행하여 V&amp;V(Verification &amp; Validation) 프로세스 전반에 적용해야한다. *</em></p>
<h2 id="소프트웨어-테스팅-단계별-프로세스-stages-of-testing">소프트웨어 테스팅 단계별 프로세스 (Stages of Testing)</h2>
<blockquote>
<p>소프트웨어 테스팅은 시간 흐름 및 목적에 따라 크게 <strong>1) Development Testing, 2) Release Testing, 3) User Testing</strong> 의 3단계로 나뉜다.</p>
</blockquote>
<h2 id="1단계-개발-테스트-development-testing">1단계: 개발 테스트 (Development Testing)</h2>
<p>시스템을 개발하는 내부 팀이 중심이 되어 버그와 결함을 발견하기 위해 직접 수행하는 과정으로, 범위에 따라 3단계로 세분화된다.</p>
<h3 id="단위-테스트-unit-testing">단위 테스트 (Unit testing):</h3>
<p>개별 기능, 메서드, 객체 클래스 등을 <strong>완벽히 격리된 상태에서 테스트하는 &#39;결함 테스트&#39;</strong> 이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/cedce587-a849-4e2a-9e2d-fb5ea77e5965/image.png" alt=""></p>
<p>Unit Testing의 전략으로는 <strong>&#39;방어벽(Barricade) 모듈&#39;</strong> 을 두는 것이 있다. 신뢰할 수 없는 오염된 외부 입력 데이터를 정상 입력과 비정상 입력으로 걸러내고 정제하여 안전 구역(Clean Area) 내의 내부 클래스들은 검증된 정상 입력만을 처리하도록 설계하여 테스트한다.</p>
<p>또한 자동화라는 기술도 존재하는데, 이는 수동 개입으로 인한 비효율을 막기 위해 실행과 결과가 자동으로 확인되도록 <strong>가급적 자동화(Automated)가 되어야한다.</strong> 90년대 중반 Kent Beck이 Smalltalk용 xUnit을 개발한 이후, 현재는 Java를 위한 JUnit (Eclipse 등 IDE에 통합)이 테스트 주도 개발(TDD)의 표준 도구로 자리 잡았으며, 다양한 언어(C++, Python 등)로 확장되었다.</p>
<h3 id="컴포넌트-테스트-component-testing">컴포넌트 테스트 (Component testing):</h3>
<p>여러 개별 객체가 통합된 복합 컴포넌트를 테스트합니다. 하위 객체들의 단위 테스트가 끝났다고 가정하고, 구성 요소 간의 인터페이스가 명세대로 동작하는지 확인하는지를 점검한다.</p>
<p>이때 인터페이스 유형은 데이터나 변수를 넘겨주는 <strong>파라미터 전달(Parameter)</strong>, 특정 메모리 블록을 공유하는 <strong>공유 메모리(Shared memory)</strong>, 서브 시스템 간 서비스 요청인 <strong>메시지 전달(Message passing) 인터페이스</strong> 등이 있다.</p>
<h4 id="interface-errors">Interface Errors</h4>
<p>주로 발견되는 Interface Errors 를 살펴보자면 아래의 3가지 경우로 나눌 수 있다. </p>
<p><strong>- Misuse</strong>
    - 파라미터 순서를 잘못 넣는 등 호출하는 컴포넌트가 인터페이스를 잘못 사용하는 경우
<strong>- Misunderstanding</strong>
    - 호출하는 측이 호출받는 쪽의 동작 방식에 대해 잘못된 가정을 하여 발생하는 오류, 
<strong>- Timing errors</strong>
    - 데이터를 요청하는 쪽과 제공하는 쪽의 작동 속도가 달라서 과거의 잘못된 정보에 접근하는 오류</p>
<h3 id="시스템-테스트-system-testing">시스템 테스트 (System testing):</h3>
<p>개발 테스트의 가장 마지막 단계로, <strong>모든 단위와 컴포넌트(외부의 기성 시스템이나 타 팀이 개발한 모듈 포함)를 하나로 통합하여 전체 시스템을 테스트</strong>한다. 완전히 통합된 환경에서 컴포넌트들이 정상적으로 호환되는지, 적절한 시점에 올바른 데이터를 전송하며 상호작용하는지를 점검한다.</p>
<p>개별 모듈 단위에서는 관찰할 수 없고 결합된 상태에서 비로소 나타나는 비기능적 요구사항인 <strong>창발적 특성(Emergent Behavior)</strong> 를 확인할 수 있는 필수적 단계라고 볼 수 있으며, <strong>개발팀이 수행하는 시스템 테스트는 여전히 내부 시스템의 버그를 찾아내기 위한 결함 테스트에 목적을 둔다</strong>는 점에서 2단계인 Release Testing과는 명확하게 구별되고 1단계인 Development Testing에 포함된다.</p>
<h3 id="2단계-릴리스-테스트-release-testing">2단계: 릴리스 테스트 (Release Testing)</h3>
<p>릴리스 테스트는 개발팀 외부에서 사용할 목적으로 특정 소프트웨어의 릴리스 버전을 테스트하는 것을 말한다. 고장 여부, 명세된 기능과 성능, 신뢰성을 제대로 제공하는지를 확인하는 단계로 볼 수 있다.</p>
<p>주 목적은 결함 테스트(Defect Testing)인 개발 테스트와 다르게 시스템이 외부 사용자를 위해 제공되기에 충분히 훌륭한지에 대해 확신을 주기 위한 <strong>확인 테스트(Validation Testing)</strong> 의 성격을 가지고, 또한 명세서의 내용에만 의존하여 테스트를 설계하기에 <strong>블랙박스(Black-Box) 테스팅</strong>으로 진행된다. </p>
<p>이외에도 여러 테스트를 진행하게되는데, 사용자의 실제 사용 프로필을 반영해 시스템 성능이 허용 범위를 넘어서 수용할 수 없을 때까지 부하를 꾸준히 증가시키는 <strong>성능 테스트</strong>와 고장이 났을 때의 반응을 볼 수 있는 <strong>스트레스 테스트</strong>도 수행한다.</p>
<h3 id="3단계-사용자-테스트-user-testing">3단계: 사용자 테스트 (User Testing)</h3>
<p>시스템 내부에서 아무리 포괄적인 테스트를 거치더라도 사용자의 실제 작업 환경에서 발생하는 예상치 못한 영향(신뢰성, 성능, 내구성 등)을 테스트 환경이 완벽히 복제할 수는 없으므로, 고객과 잠재 사용자가 직접 시스템 테스트에 참여하는 필수 단계다.</p>
<p>총 3가지의 테스트로 분류되며, 첫째로 <strong>1)알파 테스트 (Alpha testing)</strong> 는 실제 사용자가 시스템 &#39;개발자 측의 사이트(환경)&#39;에 와서 개발팀과 함께 소프트웨어를 테스트하는 것을 말하고 다음인 <strong>2)베타 테스트 (Beta testing)</strong> 는 다수의 일반 사용자에게 소프트웨어 릴리스를 배포하여, 사용자들 &#39;자신의 환경&#39;에서 자유롭게 실험해 보고 발견된 문제점들을 개발팀에 제기하도록 한다. 마지막으로 <strong>3)인수 테스트 (Acceptance testing)</strong> 는 최종 고객이 이 소프트웨어 시스템을 개발팀으로부터 인수하여 고객의 실제 운영 환경에 공식적으로 배포(deploy)할 것인지를 최종 결정하기 위해 직접 수행하는 과정을 말한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW 공학 및 테스팅 (8) - Embedded SW & Dependable SW]]></title>
            <link>https://velog.io/@woong_crouch/SW-%EA%B3%B5%ED%95%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8C%85-8-Embedded-SW-Dependable-SW</link>
            <guid>https://velog.io/@woong_crouch/SW-%EA%B3%B5%ED%95%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8C%85-8-Embedded-SW-Dependable-SW</guid>
            <pubDate>Sat, 11 Apr 2026 12:28:27 GMT</pubDate>
            <description><![CDATA[<h2 id="embedded-software">Embedded Software</h2>
<p>대규모 데이터의 분류와 저장, 검색에 초점을 맞추는 일반적인 정보 시스템과 달리, 임베디드 시스템은 <strong>더 큰 시스템 내부에 논리적으로 통합된 부품으로서 연산 자체가 주 목적이 아닌 시스템</strong>을 말한다.</p>
<p><strong>대규모이며 수명이 길고, 실시간 응답</strong>과 <strong>고장시 안전을 보장하는 신뢰성</strong>이 필수적이다. 또한 <strong>비동기적</strong>이고 <strong>병렬적인 특성</strong>을 가지며 <strong>분산된 환경에서도 동작</strong>하는 경향이 있다.</p>
<h3 id="응답-속도에-따른-분류">응답 속도에 따른 분류</h3>
<p>응답 속도에 따라 <strong>일괄 처리(batch), 대화형(interactive on-line), 실시간 시스템(real-time)</strong>으로 분류할 수 있다.</p>
<p>이 때 batch 시스템은 결과가 언제 오는지는 상관하지 않는다. 실시간 시스템(real time)은 time-deadline이 존재하는 시스템을 말한다.</p>
<h3 id="실시간-시스템의-임계성">실시간 시스템의 임계성</h3>
<p>데드라인의 엄격성으로 Hard와 Soft로 구분이 가능하고 실행 속도에 따라 Fast와 Slow로 구분할 수 있다. 
<img src="https://velog.velcdn.com/images/woong_crouch/post/ece7966e-0cd0-4c17-9dcc-c6d64ef17a1d/image.png" alt=""></p>
<h3 id="임베디드-시스템-특징">임베디드 시스템 특징</h3>
<p>임베디드 시스템을 설계할 때, 3가지의 특성을 중심으로 고려해야하는데 <strong>환경, 성능, 고장 모드</strong> 이렇게 3가지로 이뤄진다. 이 3가지 모두를 고려할 수 있어야 한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/cf4228b7-f644-4062-a42b-4e0e53bd9ef6/image.png" alt=""></p>
<h4 id="1-environmental-aspects">1. Environmental Aspects</h4>
<p>임베디드는 일반적으로 PC와 달리 <strong>물리,전기적으로 가혹한 환경에 노출되는 경우가 많아 이를 견딜 수 있어야한다.</strong> 그래서 온도, 전기적 간섭이 강한 공간, 장기 유지보수의 설계까지 반영되어야한다.</p>
<h4 id="2-performance-aspect">2. Performance Aspect</h4>
<p>임베디드 시스템의 설계자는 시스템이 <strong>환경과 상호작용하며 내야하는 성능을 예측해야한다.</strong> 정해진 주기에 따라 지속적으로 백그라운드에서 수행되어야하고, 외부의 무작위 이벤트를 즉각 반응해서 처리해야한다.</p>
<h4 id="3-failure-and-their-effects">3. Failure and their effects</h4>
<p>시스템의 하드웨어나 소프트웨어는 수명 주기 내에 어떤 이유로든 반드시 <strong>고장이 발생할 수밖에 없다는 것을 전제</strong>로 한다. 따라서 예외 처리 매커니즘을 필수적으로 포함해야한다.</p>
<h2 id="dependable-software">Dependable Software</h2>
<h3 id="3가지-품질-속성">3가지 품질 속성</h3>
<p><strong>신뢰성있는 소프트웨어(Dependable SW)</strong>는 단순히 결함이 없는 상태를 넘어 3가지 핵심 품질 속성을 충족해야한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/83ae44f3-7d06-46c2-95dc-552c993bf1fb/image.png" alt=""></p>
<ul>
<li><p><strong>정확성(Correctness)</strong>
프로그램이 <strong>요구사항 명세서와 일치하는지 나타내는 정적(static)인 속성</strong>이다. 오류가 발생하면 부정확한 결과를 보내는 것보다 아무 결과를 내보내지 않고 시스템을 멈추는 것이 낫다는 것을 의미한다.</p>
</li>
<li><p><strong>신뢰성(Reliability)</strong>
프로그램이 요구되는 정밀도에 맞춰 <strong>의도된 기능을 실제로 얼마나 잘 수행하는지 나타내는 동적(dynamic)인 속성</strong>이다. 런타임 중에 고장이 발생하는 빈도를 최소화해서 서비스가 중단 없이 유지되도록 하는 것이 중요하다는 것이다.</p>
</li>
<li><p><strong>안전성(Safety)</strong>
시스템이 정상적이거나 <strong>비정상적인 상황에서 작동하더라도 인명 피해나 재산상의 손상을 초래하는 위험없이 작동할 수 있는 능력</strong>이다. 고장이 나더라도 그것이 치명적인 사고로 이어지지 않도록 방어하는 것이다.</p>
</li>
</ul>
<h3 id="고장-발생-시-시스템-동작-전략">고장 발생 시 시스템 동작 전략</h3>
<p>완벽한 소프트웨어는 없으므로 고장이 발생하면 시스템이 어떻게 반응하고 대처할 것인지를 4가지 전략에 따라 동작한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/3b1baaf6-7dd6-4cb0-8c14-7f6f2e5c0036/image.png" alt=""></p>
<ul>
<li><strong>Fail-operational (운영 유지)</strong>: 고장이 발생한 상황에서도 <strong>전체 서비스를 온전히 유지하며 작동</strong>하는 방식이다.</li>
<li><strong>Fail-soft (성능 저하 운영)</strong>: 고장이 존재할 때 시스템의 <strong>성능이나 서비스 수준은 어느 정도 저하되더라도, 동작 자체는 계속해서 유지</strong>하는 방식이다.</li>
<li><strong>Fail-hard (즉시 중단)</strong>: 고장이 발생하면 <strong>전체 시스템을 즉시 완전히 멈추게(Halt)</strong> 하는 방식이다.</li>
<li><strong>Fail-safe (안전 중심 중단)</strong>: 정상적인 시스템 운영을 복구하려고 노력하는 대신, 고장으로 인해 발생할 수 있는 <strong>위험이나 피해를 제한하고 최소화하는 데 목적</strong>을 두는 방식이다.</li>
</ul>
<h2 id="software-error">Software Error</h2>
<h3 id="소프트웨어-오류의-3가지-범주">소프트웨어 오류의 3가지 범주</h3>
<p>소프트웨어 오류란 오작동을 일으키는 프로그램의 요소들을 총괄한 내용인데, 크게 3가지 범주로 나눌 수 있다.</p>
<p><strong>시스템 설계 오류</strong>
설계자가 시스템이 작동할 물리적 환경이나 동작 시간에 대해 잘못된 가정을 내렸을 때 발생하는 치명적 오류이다.</p>
<p><strong>설계 및 코딩 오류</strong>
개념을 실제 컴퓨터 코드로 번역하는 과정에서 발생한다. 우리가 흔히 생각하는 개발 중에 일어나는 오류들이 거의 대부분 여기에 포함된다. 소프트웨어가 고객의 의도나 의미를 잘못 이해한 <strong>의미론적 오류</strong>, 우발적 무한루프, 데드락 등의 <strong>논리적 오류</strong>, 0으로 나누기나 오버플로우 등의 <strong>알고리즘적 오류</strong> 등으로 구성된다.</p>
<p><strong>환경적 요인</strong>
소프트웨어가 정상적인 환경에서 작동할 때 발생하는 하드웨어의 오작동, 사람의 실수, 예상치 못한 외부 간섭 등 <strong>예측 불가능한 오류</strong>이다. 이는 설계 단계에서 완벽하게 제거할 수 없기에 심층 분석으로 문제 발생 가능성을 최소화 해야한다.</p>
<h2 id="좋은-소프트웨어-설계를-위한-원칙">좋은 소프트웨어 설계를 위한 원칙</h2>
<p>나쁜 소프트웨어가 만들어지는 원인은 경영진 또는 상관에게 문제가 있거나 설계가 부족한 상황, 전문성 결여, 문서화 부족, 프로토타이핑 부재 등의 여러 문제들을 꼽을 수 있다.</p>
<p>그럼 반면 좋은 소프트웨어 개발의 기본은 무엇일까 <strong>1) 우선 명확한 요구사항이 정의</strong>되어야 한다. 사용자가 무엇을 원하는지 잘 파악하는것이 중요하다는 것이다. 그리고 <strong>2)설계를 할 때 목표 달성이 가능한 수준</strong>이어야하고, <strong>3)관리에 있어서 유연한 프로젝트 조직으로 구성</strong>이 되어야한다. 마지막으로 <strong>4)테스트가 쉽게 이뤄지도록 설계와 검증된 방법을 사용</strong>하는 것이 필요하다.</p>
<p>이식성과 재사용성 또한 좋은 소프트웨어 하면 빠질 수 없는데, 검증된 컴포넌트를 사용해서 작업을 하면 설계, 코딩, 디버깅 시간 및 비용이 감소하고 신뢰성을 높일 수 있다. 이식성과 재사용성을 고려하면 소프트웨어가 더욱 효율적으로 구성될 수 있다.</p>
<h2 id="defensive-programming">Defensive Programming</h2>
<h3 id="오류-회피와-방어적-프로그래밍">오류 회피와 방어적 프로그래밍</h3>
<p>우리는 기본적으로 오류에 대해 회피를 해야한다. 오류를 회피한다는게 무슨말이냐, _오류 회피는 기본적으로 잘못된 값이 들어오거나 잘못된 접속이 발생했을 때 큰 문제가 발생하지 않으면 가능한 회피_하는 방향으로 움직이는 것이다. 이러한 오류 회피를 실질적인 프로그래밍에 접목하면 <strong>&quot;방어적 프로그래밍&quot;</strong>이 된다. </p>
<p>방어적 프로그래밍은 예상치 못한 입력에도 소프트웨어가 계속 수행을 보장할 수 있도록 한 프로그래밍 기법이다. 방어적 프로그래밍은 목표가 존재하는데 <strong>오류가 발생했을 때, 도입 자체를 방지하고, 발생 시 감지는 필수적이며 마지막으로 시스템의 반응을 제어</strong>한다.</p>
<p>방어적 프로그래밍이 모토로 이끄는 문장이 있는데 <strong>&quot;Garbage in, nothing out&quot;</strong>이라고 하며, 좋은 프로그램은 잘못된 값이 들어오면 이를 아무것도 내보내지 않는 방식으로 방어해야한다.</p>
<h3 id="단언문assertion의-활용과-가이드-라인">단언문(Assertion)의 활용과 가이드 라인</h3>
<p><strong>단언문</strong>이란 개발 중에 프로그램이 예상대로 작동하는지 <strong>스스로 확인하도록 하는 코드</strong>이다. 복잡한 프로그램에서 잘못된 인터페이스나 코드 수정시에 발생한 오류를 빠르게 찾아내는 데에 유용하다. 주로 절대 발생하면 안되는 조건에만 사용한다.</p>
<p>그리고 <strong>Assertion 내에는 실행코드를 넣으면 안된다.</strong> 만약 넣게되면 그 코드가 배포 등을 했을 경우 무시될 가능성이 존재하기 때문이다. 그리고 마지막으로 사전 조건과 사후 조건을 문서화하고 검증할 때도 사용한다.</p>
<h2 id="exception-handling">Exception Handling</h2>
<h3 id="오류처리-기법">오류처리 기법</h3>
<p>오류를 처리하는 기법은 여러가지가 있는데 아래에 간결하게 정리해보면 다음과 같다.</p>
<ul>
<li><strong>중립적인 값 반환</strong> : 안전한 값을 반환하는 방식이다.</li>
<li><strong>다음의 유효한 데이터로 대체</strong> : 손상된 기록을 건너뛰고 다음 값을 넣는다.</li>
<li><strong>이전과 동일한 응답 반환</strong> : 이전에 출력한 값을 이어서 출력하는 형태이다.</li>
<li><strong>가장 가까운 합법적 값으로 대체</strong> : 최대/최소 허용치로 값을 조정한다.</li>
<li><strong>파일에 경고 메세지 기록</strong> : 메세지만 남기고 계속 수행한다.</li>
<li><strong>에러 코드 반환</strong> : 예외 처리를 통해서 오류의 발생을 알린다.</li>
<li><strong>에러 처리 루틴/객체 호출</strong> : 중앙 집중식이며 코드를 재사용할 때 종속성을 계속 호출해야한다.</li>
<li><strong>에러 발생 위치에 바로 메세지 표시</strong> : 흔히 단순히 생각하는 출력구문을 이용하는 것이다.</li>
<li><strong>가장 적합한 최소한의 방법으로 처리</strong> : 유연성은 높지만 시스템 전체의 정확성/강건성은 못 맞출 수 있다.</li>
<li><strong>시스템 종료</strong> : 안전 필수 애플리케이션에서 유용하다.</li>
</ul>
<h3 id="딜레마--강건성robustness-vs-정확성">딜레마 : 강건성(Robustness) vs 정확성</h3>
<p>강건성과 정확성이 있다. 여기서 _<strong>강건성</strong>_이란, 소프트웨어가 중단되지 않고 어떻게든 작동하도록 하는 것을 말한다. 설령 <strong>기능적으로 성능이 저하되더라도 실행시키는 것</strong>에 의미를 둔다. 반대로 _<strong>정확성</strong>_이란 소프트웨어가 고장이나 에러가 발생하면 심각한 문제를 초래할 가능성이 높기에 <strong>부정확한 결과보다 아예 결과 자체를 반환하지 않는 것</strong>을 말한다.</p>
<p>소프트웨어는 그 종류에 따라서 강건성을 더 중요시할수도, 정확성을 중요시할수도 있다. 만약 에어백이나 방사선 치료기와 같이 조금의 문제도 발생해서는 안되는 기기에는 정확성을 요할 것이고, 그냥 우리가 자주 쓰는 유튜브나 서비스 프로그램들은 강건성에 힘을 더 주어서 중단되지 않고 이어가는 것을 중요시해야한다.</p>
<h3 id="프로그래밍-언어-수준의-예외처리">프로그래밍 언어 수준의 예외처리</h3>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/804b96cd-ccbd-48f5-99d7-8beeaa0dd100/image.png" alt="">
<code>Exception</code>은 코드가 스스로 처리하지 못하는 <strong>예기치 않은 예외 이벤트를 마주쳤을 때, 이를 자신을 호출한 코드쪽으로 전달하는 특정 매커니즘</strong>이다. 언어에 따라서 예외처리를 하는 표현의 방식은 다르다는 점을 유의해서 접근해야한다.</p>
<br>
<br>

<p>이렇게 <strong>임베디드 시스템</strong>와 관련된 내용을 알아보았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Software Engineering & Testing (7) - Design Patterns & Behavioral Model]]></title>
            <link>https://velog.io/@woong_crouch/Software-Engineering-Testing-7-Design-Patterns-Behavioral-Model</link>
            <guid>https://velog.io/@woong_crouch/Software-Engineering-Testing-7-Design-Patterns-Behavioral-Model</guid>
            <pubDate>Wed, 08 Apr 2026 02:57:09 GMT</pubDate>
            <description><![CDATA[<h2 id="introduction">Introduction</h2>
<p>디자인 패턴은 대규모 시스템 설계에서 특히 중요한 지점을 가진다.</p>
<p>공통의 설계 어휘를 통해서 <strong>1) 개발자들간의 의사소통을 명확</strong>하게 가져갈 수 있고, <strong>2) 설계 복잡성이 감소</strong>하고 재사용성을 촉진한다. 또한 <strong>3) 시행착오를 방지</strong>하고 <strong>4) 유지보수성을 향상</strong>시키는 장점을 가진다.</p>
<p>패턴의 목적에 따라서 <strong>생성, 구조, 행위 패턴</strong>으로 구분해서 분류한다.</p>
<h2 id="인터페이스-관점의-상속">인터페이스 관점의 상속</h2>
<h3 id="상속을-통한-내부-은폐">상속을 통한 내부 은폐</h3>
<p>인터페이스 관점에서 <strong>상속은 내부 은폐의 도구로 사용</strong>되기도 한다. 클라이언트에게 Parent 클래스만 보이게 하여 내부의 복잡한 상황들을 숨긴다. 
<img src="https://velog.velcdn.com/images/woong_crouch/post/4658772a-b27a-4ac9-a31a-0c971565a323/image.png" alt=""></p>
<p>Parent로 Child를 Abstract했다고도 볼 수 있다. 주로 서브 시스템 간의 커뮤니케이션에서 잘 사용된다.</p>
<h3 id="재귀적-구조-정의">재귀적 구조 정의</h3>
<p>재귀적인 구조관계를 상속으로 정의할 수 있는데 디렉토리는 파일이기도 하지만 파일을 포함하고 또 다른 디렉토리도 포함한다. </p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/be0ef310-4fe9-4f87-8a23-ba5f09643d08/image.png" alt=""></p>
<p>이걸 단순하게 이야기해서 결론만 도출하면 <strong>클라이언트에게 모두 File 클래스로만 인지</strong>되며 <strong>내부의 복잡한 재귀적인 정의들은 숨겨버린다.</strong></p>
<h2 id="생성-패턴-creational-design-patterns">생성 패턴 (Creational Design Patterns)</h2>
<h3 id="singleton">Singleton</h3>
<p>하나의 애플리케이션 내에서 특정 클래스의 <strong>인스턴스를 오직 하나만 생성해 보장</strong>하고, 어디서든 그인스턴스에 접근할 수 있도록 하는 생성 디자인이다.</p>
<p>시스템 전체를 포괄적으로 관리해야 하는 객체는 <strong>무분별하게 여러 개의 객체가 만들어지는 것을 통제</strong>해야할 때 사용된다. 구현 원리는 아래와 같다.</p>
<h4 id="생성자-은닉">생성자 은닉</h4>
<p>클라이언트가 <code>new</code> 키워드를 이용해 함부로 인스턴스를 만들지 못하도록 <strong>생성자를 <code>protected</code>나 <code>private</code>로 숨긴다.</strong></p>
<h4 id="static-변수와-메서드-활용">Static 변수와 메서드 활용</h4>
<p>클래스 내부에 유일한 인스턴스를 저장할 <code>static</code> 포인터를 둔다. <strong>외부에서는 <code>instance()</code>라는 <code>static</code> 메서드만으로 객체에 접근</strong>한다</p>
<h4 id="지연-생성">지연 생성</h4>
<p><code>instance()</code> 메서드가 호출되면, <strong>인스턴스가 없는 경우(NULL), 최초로 하나 생성하고, 이미 생성된 경우 기존의 것을 그대로 반환</strong>한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/1540a96c-0904-458f-8c7f-fea3115cdbfa/image.png" alt=""></p>
<h3 id="prototype">Prototype</h3>
<p>생성할 객체의 종류를 명시하는 Prototypee 객체를 만들어두고 새로운 객체가 필요할 때, 구체적인 생성자(<code>new</code>)를 부르는 대신 이 객체를 Clone하여 새로운 객체를 만든다.</p>
<h4 id="clone-메서드-활용">Clone() 메서드 활용</h4>
<p>미리 만들어둔 원형의 객체(Prototype)에 자신을 복제하는 <code>Clone()</code> 메서드를 정의해둔다.</p>
<h4 id="클라이언트-추상화">클라이언트 추상화</h4>
<p>상위 인터페이스(prototype)에 <code>Clone()</code>을 호출하기만 하면 실제 할당된 객체가 무엇이든 알아서 새 객체가 만들어진다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/c1687351-1123-49ca-8233-d69379c9e2fb/image.png" alt=""></p>
<h2 id="구조-패턴-structural-design-patterns">구조 패턴 (Structural Design Patterns)</h2>
<h3 id="facade">Facade</h3>
<p>내부와 외부 시스템은 강한 연결을 하지 않는다. 내/외부의 시스템을 연결할 때, facade interface를 만들어 이를 통해서만 소통하게 한다.약한 연결로 소통하는 방식으로 이어간다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/4d1cccca-8cbf-41f0-9a82-7ed4a6b08215/image.png" alt=""></p>
<p>클라이언트가 서브 시스템의 내부를 알 필요 없이 퍼사드(창구)하고만 통신하므로서 의존성을 최소화하고 로직이 변해도 클라이언트에게 영향이 덜해 유지보수도 쉽다.</p>
<h3 id="adapter">Adapter</h3>
<p>우리가 생각하는 그 어댑터가 맞다. 각기 따로 개발된 클래스나 외부 라이브러리를 수정없이 기존 시스템에 통합할 수 있다. 호환성을 보장해주기 위해 존재하며 클라이언트가 원하는 target 인터페이스로 변환해주는 패턴이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/f9f510b1-8864-4b1c-acad-af093a5b6fdf/image.png" alt=""></p>
<h3 id="composite">Composite</h3>
<p>부분-전체 관계를 나타내기 위해 객체들을 트리로 구성하는 패턴으로, 클라이언트가 단일 객체와 이들이 묶인 복합 객체를 동일한 방식으로 취급한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/d567f126-8d44-43af-9918-0491e7417835/image.png" alt=""></p>
<h2 id="행위-패턴-behavioral-design-patterns">행위 패턴 (Behavioral Design Patterns)</h2>
<h3 id="template-method">Template Method</h3>
<p>여러 클래스에서 <strong>공통으로 사용되는 메서드를 템플릿화하여 상위 클래스에서 정의</strong>하고 <strong>하위 클래스마다 세부 동작 사항을 다르게 구현</strong>하는 것이다. 
<img src="https://velog.velcdn.com/images/woong_crouch/post/c9468b72-8169-4d62-8e2c-f85ad3a22c20/image.png" alt=""></p>
<p><strong>변하지 않는 기능들만 상위 클래스</strong>에 두고 <strong>자주 변하는 기능들을 하위 클래스에 둠</strong>으로서 하위 클래스를 수정해서 업로드하면 상위 클래스에 잘 적용되는 것을 목적으로 한다.</p>
<h3 id="observer-pattern">Observer Pattern</h3>
<p>옵저버 패턴은 <strong>옵저버들이 관찰하고 있는 대상의 상태가 변하면</strong> 대상이 <strong>옵저버들에게 통지하고 옵저버들은 알림을 받고 조치</strong>하는 행동 패턴이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/5176dfec-0170-412b-bdc8-f4872b4e0f07/image.png" alt=""></p>
<p>다른 디자인 패턴들과는 다르게 <strong>one-to-many의 의존성</strong>을 가진다. 일종의 interactive한 디자인 패턴이라고 볼 수 있다.</p>
<h2 id="행위-모델--sequence-diagram">행위 모델 : Sequence Diagram</h2>
<h3 id="syntax">Syntax</h3>
<p>철저히 클래스가 아닌 객체 단위로 그려야한다. 아래에 표기법과 관련된 내용을 그림으로 정의해둔다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/5d5d5946-0eb6-4730-99d8-6dfb695918bd/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/a5877b4d-f1a3-4925-b0ea-c4a5acdb2700/image.png" alt=""></th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/58b9d7bb-16eb-46c5-a3cb-5e1e4d8a535c/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/6d8ad70d-f75c-43c7-ab53-75faa1fd86c5/image.png" alt=""></th>
</tr>
</thead>
</table>
<h3 id="메세지의-주요-유형">메세지의 주요 유형</h3>
<p>메세지는 객체 간 서비스를 호출하는 리퀘스트를 의미하며, 화살표의 모양에 따라 실행 방식이 다르다.</p>
<p><strong>Asynchronous message</strong>는 선으로만 된 화살표로, 상대의 처리 완료를 기다리지 않고 바로 다음 작업을 병렬로 진행한다.</p>
<p><strong>Call message</strong>는 꽉찬 화살표로, 호출한 객체는 수신한 객체의 작업이 끝나고 리턴될 때까지 기다린다.</p>
<p><strong>Reply message</strong>는 점선 화살표로 표기하며 처리가 끝나면 제어권과 결과값을 원래 객체에 돌려주는 메세지다.</p>
<p><strong>Lost message</strong>는 외부 알 수 없는 곳으로 날아가는 예외적인 이벤트의 흐름을 나타낸다</p>
<p><strong>Found message</strong>는 외부 알 수 없는 곳에서 날아오는 예외적인 이벤트의 흐름을 나타낸다</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/f2604023-fd9e-4cba-a600-c988e46173d1/image.png" alt=""></p>
<h3 id="combinded-fragments">Combinded Fragments</h3>
<p>기존의 시퀀스 다이어그램에서 if문이나 반복문을 표현하기 어려웠으나 UML 2.0부터 <strong>복합 프레그먼트</strong>를 도입하여 로직을 표현한다. </p>
<p><strong><code>alt</code>는 if-else 조건문</strong>을 나타내고, <strong><code>opt</code>는 조건이 참일 때만 실행되는 단일 if문</strong>이다. <strong><code>loop</code>는 특정 조건을 만족하는 동안 메세지 교환을 반복</strong>하며 <strong><code>par</code>은 여러 흐름이 동시에 수행</strong>됨을 의미한다. </p>
<p><strong><code>neg</code>는 절대 발생해서는 안되는 시나리오</strong>를 나타내고, <strong><code>assert</code>는 반드시 발생해야하는 올바른 흐름</strong>을 나타낸다. 마지막으로 <strong><code>critical</code>은 임계 영역(병렬 상황에서 한번에 실행을 보장)</strong>을 나타낸다.</p>
<p>추가로 <strong><code>ref</code></strong>도 존재하는데, <strong>외부의 시퀀스 다이어그램을 참조하기 위해 가져다 쓰는 것</strong>을 의미한다.</p>
<h3 id="pitfalls-in-sequence-diagram">Pitfalls in Sequence Diagram</h3>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/d6edc894-3355-427b-af8d-710db0540897/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/fe010a58-e5a7-46a7-8758-4265e2afa5cd/image.png" alt=""></th>
</tr>
</thead>
<tbody><tr>
<td><img src="https://velog.velcdn.com/images/woong_crouch/post/3071eac4-e246-404f-92a3-35100fb2c553/image.png" alt=""></td>
<td><img src="https://velog.velcdn.com/images/woong_crouch/post/50f24090-2dfd-432c-9a5d-13fa131e001d/image.png" alt=""></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW Engineering & Testing (6) - Structural Modeling]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-5</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-5</guid>
            <pubDate>Mon, 06 Apr 2026 13:11:18 GMT</pubDate>
            <description><![CDATA[<h1 id="structural-models">Structural Models</h1>
<p>구조적 모델은 &quot;무엇이 상호작용하는가&quot;에 초점을 맞춰서 시스템의 정적인 구조와 뼈대를 모델링하는 것이 주의 핵심이다. </p>
<h3 id="구조적-모델의-목적">구조적 모델의 목적</h3>
<p>객체는 <strong>Application Domain에서 핵심이 되는 사물, 아이디어, 개념 등을 나타내는 것</strong>이다. 클래스 다이어그램, 오브젝트 다이어그램을 작성하기 위한 규칙이나 스타일 지침 그리고 구조 모델간의 관계를 이해하는 것을 목적으로 한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/4803eb16-90f8-46b1-b266-6c24f72b9118/image.png" alt="">
Structural 모델의 가장 주요한 목표는 <strong>문제 영역에 포함된 핵심 데이터를 발견하고 객체의 구조적 모델을 구축</strong>하는 것이다. </p>
<h3 id="구조적-viewpoint">구조적 ViewPoint</h3>
<p><strong>ViewPoint를 표현하기 위해서 다양한 다이어그램을 제공</strong>하고, 컴포넌트 다이어그램부터 클래스 다이어그램, 객체 다이어그램 등이 대표적으로 활용된다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/19d11cbd-afb8-4f21-9d35-dc680cf0cb17/image.png" alt=""></p>
<h2 id="class-diagram">Class Diagram</h2>
<p>클래스 다이어그램에서는 시스템의 정적인 구조를 구성하는 핵심 단위인 <strong><code>클래스</code>는 사각형 박스</strong>로 그려지고, 내부적으로 크게 3가지의 엘리먼트로 나누어 표현된다. </p>
<h3 id="class-name">Class Name</h3>
<p>말 그대로 <strong>클래스의 이름</strong>을 보이며, 가장 위칸에 위치하고 문제 도메인에서 식별된 해당 객체의 이름을 나타낸다.</p>
<h3 id="attributes">Attributes</h3>
<p>이름 다음에 오는 중간 칸을 이용하며, 클래스가 <strong>내부적으로 관리하고 유지하는 데이터</strong>를 의미한다. </p>
<p>표기법은 아래와 같다.
<strong>[visible] name : type-expression [=initial-value]</strong></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/cf922c23-1717-41f0-9b87-458c7d3b0033/image.png" alt=""></p>
<h4 id="가시성visibility">가시성(Visibility)</h4>
<p>이 때, Visibility는 총 3가지로 표기할 수 있는데, 우선 <strong><code>+</code>는 public을 의미하며 외부의 누구나 접근 가능</strong>하고, <strong><code>-</code>는 반대로 private를 의미해 해당 클래스 내부에서만 접근 가능</strong>하다. 마지막으로 <strong><code>#</code>은 protected를 의미해 자식 클래스에게만 접근을 허용</strong>한다.</p>
<h4 id="정적-인스턴스">정적 인스턴스</h4>
<p>속성 밑에 밑줄이 그어서 표기하며, 클래스 차원에서 메모리에 유일하게 하나만 존재하여 공유되는 정적(Static) 변수를 의미한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/52e3a7ed-431e-44f2-bc55-b481e0bcc90b/image.png" alt=""></p>
<h3 id="operation">Operation</h3>
<p>가장 아랫쪽 칸을 차지하며, 클래스가 외부 클라이언트에게 제공하는 서비스를 정의한다. </p>
<p>표기법은 아래와 같다.
<strong>[visibility] name([parameter-list]) [: return-type]</strong></p>
<p>속성과 마찬가지로 오퍼레이션에 밑줄이 그어져 있으면 Static Method를 뜻한다.</p>
<h2 id="클래스-간의-주요-관계">클래스 간의 주요 관계</h2>
<h3 id="generalizationinheritance">Generalization(Inheritance)</h3>
<p>is-a가 성립하는 부모-자식 간의 관계를 나타낸다. 여러 클래스를 분석하다 공통적인 부분(Attribute or Operation)이 발견되면, 이를 <strong>부모 클래스로 뽑아 올려 중복을 없애고 코드를 재사용하기 위해 사용되는 관계</strong>이다. <strong>속이 빈 삼각형 화살표와 실선</strong>으로 표기한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/5d0ccea3-26e0-462b-990e-725d3a461e5e/image.png" alt=""></p>
<h3 id="aggregationcomposition">Aggregation(Composition)</h3>
<p>전체와 부분을 나타내는 part-of 관계를 가진다. 두 클래스의 결합 강도에 따라서 다음의 두 관계로 세분화할 수 있다. </p>
<h4 id="strong-aggregationcomposition">Strong Aggregation(Composition)</h4>
<p>전체와 부분의 생명주기가 동일한 매우 강한 결합의 형태이다. 전체 객체가 소멸하거나 생성될 때, <strong>부품 component도 동시에 생성되고 소멸한다.</strong> 표기법으로는 <strong>속이 찬 다이아몬드</strong>로 표현된다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/8f618e5c-9049-4338-86ad-2ecd1ed8c4db/image.png" alt=""></p>
<h4 id="weak-aggregation">Weak Aggregation</h4>
<p>부품이 하나의 전체에만 전담되지 않고 <strong>여러 다른 객체에서 공유될 수 있는</strong> 결합으로 속이 <strong>빈 다이아몬드로 표기</strong>한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/da1cc4a0-b023-4ca3-80a3-0aac930c062d/image.png" alt=""></p>
<h3 id="association">Association</h3>
<p><strong>상속이나 전체-부분 관계에 속하지 않는 클래스 간의 일반적인 연결 및 사용 관계</strong>를 의미한다. <strong>선으로 연결</strong>해 표현하고, 관계를 명확히 하기 위해 <strong>방향성 화살표나 역할 이름을 덧붙일 수 있다.</strong> </p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/48afb5e0-42cd-4e4f-be29-a14d3d58e4ca/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/13ffbef8-3651-4505-8117-dfbc46cd24e1/image.png" alt=""></th>
</tr>
</thead>
</table>
<p>가장 중요한 특징은 선 끝에 다중성을 명시해 하나의 객체가 상대방 객체와 몇 개의 관계를 맺는지를 나타낸다.</p>
<h3 id="dependency">Dependency</h3>
<p>Associate보다 훨씬 약한 연결로 <strong>한 클래스의 변경이 다른 클래스에 영향을 미치는 관계</strong>이다. 특정 메서드를 실행할 때, 파라미터로 전달받거나 리턴 타입으로 일시적으로만 사용할 때 주로 형성된다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/3ab5fe16-4275-410e-a238-8e85636c2307/image.png" alt="">
일반 실선이 아닌 <strong>점선 화살표로 표기</strong>하여 적용한다.</p>
<h2 id="인터페이스와-스테레오-타입">인터페이스와 스테레오 타입</h2>
<h3 id="인터페이스interface">인터페이스(interface)</h3>
<p>실제 동작하는 <strong>구현 부분 없이 외부에 제공할 Operation의 시그니처만 모아둔 집합</strong>이다.
<code>&lt;&lt;interface&gt;&gt;</code>
<img src="https://velog.velcdn.com/images/woong_crouch/post/46856203-550b-4045-9355-8e55b80a4b45/image.png" alt="">
클래스들이 직접 통신하면 서로 떼어낼 수 없는 Strong Coupling이 발생한다. 인터페이스를 둠으로서 결합의 강도가 줄어들어 Weak Coupling을 유도할 수 있다.</p>
<h3 id="스테레오-타입stereotype">스테레오 타입(Stereotype)</h3>
<p>기존에 존재하는 UML의 기본 구성 요소를 확장해 <strong>새로운 의미나 종류의 모델 요소를 만들어내는 표기</strong>법이다.</p>
<p>아래와 같은 표기법으로 나타낸다.
<code>&lt;&lt;&gt;&gt;</code>
다이어그램을 보는 사람이 해당 요소의 용도와 성격을 명확히 이해할 수 있도록 돕는 역할을 한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/a571f33e-b97e-4bf4-b7b1-f79a061e69f0/image.png" alt=""></p>
<h3 id="클래스-다이어그램-vs-객체-다이어그램">클래스 다이어그램 vs 객체 다이어그램</h3>
<p>같은 내용을 정리해도 다이어그램의 종류에 따라서 서로 다른 형태를 띈다. 아래와 같이 클래스 다이어그램과 객체 다이어그램은 서로 다른 모습을 보인다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/9d343c46-918d-4688-ad3b-b865d80bcf83/image.png" alt=""></p>
<h2 id="객체-식별-및-모델링-프로세스">객체 식별 및 모델링 프로세스</h2>
<h3 id="object-identification">Object Identification</h3>
<p>문제 도메인에 있는 어떤 아이디어나 개념을 소프트웨어 내의 클래스로 뽑아낼 것인가&quot;를 결정하는 단계이다. 총 3가지의 기법으로 클래스 후보군을 추린다.</p>
<h4 id="텍스트-분석">텍스트 분석</h4>
<p>기계적으로 분석하는 방법으로, 문장에서 명사는 클래스나 속성의 후보로, 동사는 오퍼레이션 후보로 추출한다.</p>
<h4 id="브레인-스토밍">브레인 스토밍</h4>
<p>팀원들이 한자리에 앉아 시스템에 필요할 듯한 클래스나 속성 등을 토론하며 식별하는 방식이다.</p>
<h4 id="common-object-list">Common object list</h4>
<p>비즈니스 도메인에서 보편적으로 클래스로 추출되는 대표적 유형리스트를 참고해 누락된 객체를 찾아내는 방법이다.</p>
<p>역할, 물리적 사물, 사건, 상호작용을 중심으로 알아보게 된다.</p>
<h3 id="crc-카드">CRC 카드</h3>
<p>CRC 카드는 <strong>다이어그램을 그리기 전, 설계의 결함을 조기에 찾아내고자 작성</strong>된다. 주로 Object Identification을 수행하고 작성된다.</p>
<p>Use Case 기반으로 분석을 통해서 초안을 작성하고 브레인 스토밍을 통해 토의한 이후 <strong>롤플레잉을 통해서 검증</strong>한다. 그리고 이에 대한 결함을 보완하면서 CRC 카드를 기반으로 클래스 다이어그램을 그린다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/8eb1b99e-3911-43c2-8053-0e3e4fc1f432/image.png" alt=""> CRC카드 앞</th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/d48918ff-980e-4740-834d-ffbd7216aa78/image.png" alt=""> CRC 카드 뒤</th>
</tr>
</thead>
</table>
<h3 id="클래스-유형">클래스 유형</h3>
<p>Unified Process는 3가지로 클래스를 유형을 나눠 분류한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/d124fecc-094c-4f36-a815-a5c108d563f8/image.png" alt=""></p>
<p>이 전체는 <strong>stereotype</strong>이며, UML을 정의하면 시스템을 정확히 모델링하는 데 필요한 추가 구성요소를 정의할 수 있다.</p>
<h4 id="entity-class">Entity Class</h4>
<p><strong>영구적으로 DB에 저장되고 유지되어야 하는 데이터 정보들을 기록</strong>한다. 예를 들어 계좌나, 학생, 강좌 등 프로젝트에서 중심을 가지는 데이터들 다루는 Class를 말한다.</p>
<h4 id="boundary-class">Boundary Class</h4>
<p><strong>시스템과 외부 Actor 간의 상호 작용 및 입출력을 담당</strong>한다. 위의 설명처럼 주로 input과 output과 연관된 작동을 주로 이 클래스에 분류한다.</p>
<h4 id="control-class">Control Class</h4>
<p><strong>복잡한 비즈니스 로직을 연산하거나 알고리즘을 제어하는 것</strong>을 주로 담당하는 클래스로 무언가 계산을 해야하는 로직의 경우 이 클래스로 분류된다. </p>
<h1 id="case-study">Case Study</h1>
<p>Osbert Oglesby 미술품 시스템을 중심으로 앞서 정리한 내용들을 돌아보는 과정을 거친다.</p>
<h2 id="1-system-request--use-case">1. System Request &amp; Use Case</h2>
<p>Osbert가 그림을 구매할 때 최대 지불 가능 가격을 산정하고, 미술 시장의 새로운 트렌드를 파악해 세금 계산 등을 위해 <strong>모든 판매/구매 기록을 유지하고 보고서를 출력</strong>하는 시스템을 개발하고자 한다. </p>
<p>이때, Use Case는 아래와같이 4개의 주요 Use Case로 구성된다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/e640116e-6a3f-425a-9474-3fba38a85e24/image.png" alt="">
정보 시스템을 한 단락으로 묘사해보면, <strong>&quot;예술 작품 구매 의사 결정 과정의 효과를 향상시키기 위해 보고서를 생성할 것이다. 보고서에는 걸작, 명작 및 기타 그림으로 분류되는 그림에 대한 매매 정보가 포함되어있다.&quot;</strong>로 표현할 수 있다.</p>
<h2 id="2-엔티티-식별-및-구조-고도화">2. 엔티티 식별 및 구조 고도화</h2>
<p>엔티티를 명사를 추출함으로서 식별하고, 구조를 개선하여 클래스 다이어그램을 명확하게 만들어낸다.</p>
<h3 id="명사-추출">명사 추출</h3>
<p>1) 위의 단락에서 명사만을 표기한다.
<strong>&quot;<U>예술 작품</U> <U>구매</U> 의사 결정 <U>과정</U>의 <U>효과</U>를 향상시키기 위해 <U>보고서</U>를 생성할 것이다. <U>보고서</U>에는 <U>걸작</U>, <U>명작</U> 및 <U>기타 그림</U>으로 분류되는 <U>그림</U>에 대한 <U>매매</U> <U>정보</U>가 포함되어있다.&quot;</strong></p>
<p>2) 추출 결과물을 보면 아래와 같다. 
<strong>{ 예술 작품, 구매, 과정, 효과, 보고서, 걸작, 명작, 기타 그림, 그림, 정보 }</strong></p>
<p>3) Entity Class를 추출한다.
추상명사와 동명사 등을 제외하고, 오래 지속되지 않는 것들도 제외한 뒤, 동의어를 제거하면 아래만 남는다.
<strong>{ 걸작, 명작, 기타 그림, 그림 }</strong></p>
<p>고로 이렇게 4개가 Entity Class로 선택된다.</p>
<h3 id="1차-diagram-구조-개선">1차 Diagram 구조 개선</h3>
<p>우선 <strong>각 엔티티 클래스 후보군들을 두고, 클래스 간의 상호관계를 고려</strong>한다. 관계를 보면 그림을 기준으로 나머지 클래스들과 포함 관계를 가진다. 따라서 <strong>그림(painting) 클래스를 Base Class로, 나머지를 Sub Class</strong>로 한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/866a2185-a116-46c0-8b3c-deebfcba6662/image.png" alt=""></p>
<h3 id="2차-diagram-구조-개선">2차 Diagram 구조 개선</h3>
<p>지금까지의 클래스 다이어그램을 기준으로 Pricing Algorithm을 반영하지 않았기에 이제 이 부분을 고려해야한다.</p>
<p>걸작(masterwork)을 다룰 때, 정보 시스템은 우선 같은 화가의 명작(masterpiece)인 것처럼 최대 지불 금액을 계산한다. 고로 걸작(masterwork)은 명작(masterpiece)의 모든 attribute를 가져야한다. 또한 자신의 속성도 가져야한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/a212aed6-0a6a-43f9-a27b-e3ad56c4bb88/image.png" alt=""></p>
<h3 id="3차-diagram-구조-개선">3차 Diagram 구조 개선</h3>
<p>위의 클래스에서 고려하지 못한 pricing algorithm은 경매 기록이 있는 그림과 구매를 고려중인 그림 사이의 유사도 계수를 계산한다는 것이다. </p>
<p>그렇게 되면 경매 기록이 있는 그림 클래스가 필요하다. 이는 Painting class의subclass여야 하며, 현재 전시된 그림과는 관련성이 없어서 표현하면 아래와 같이 표현한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/16166e0b-d0c8-4605-ad02-be7823e572f9/image.png" alt=""></p>
<h3 id="4차-diagram-구조-개선">4차 Diagram 구조 개선</h3>
<p>3번째까지도 <strong>fashionability 모델링이 아직이며 F*A 공식으로 상품의 최대 지불가격을 정해야한다</strong>. (F = 작가 유명도 상수, A = 그림 크기) 또한 Fashionability Class가 필요하다. 이러한 고려사항을 적용하면 아래와 같아진다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/6007c597-14fe-4283-89eb-e2b6d4f2a0d1/image.png" alt=""></p>
<h3 id="상세-클래스-다이어그램">상세 클래스 다이어그램</h3>
<p>클래스 다이어그램에 필요한 요소를 상세히 다 넣으면 아래와 같은 그림으로 그릴 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/292512fc-bbcb-413c-9860-f5773e58b0be/image.png" alt=""></p>
<h2 id="3-바운더리-클래스-식별">3. 바운더리 클래스 식별</h2>
<p>시스템과 유저간의 <strong>입력/출력을 담당하는 UI 요소를 도출</strong>한다. 4개의 Use Case 스크린을 포괄적으로 처리할 클래스를 둔다. 이후 보고서들의 내용은 각기 다르므로 <strong>3개의 독립적 보고서 클래스를 분리</strong>해 바운더리 클래스를 도출한다.</p>
<p><strong>Purchase Report, Sales Report, Future Trends Report, User Interface Class</strong></p>
<h2 id="4-컨트롤-클래스-식별-및-최종-완성">4. 컨트롤 클래스 식별 및 최종 완성</h2>
<p><strong>데이터를 가공하고 계산하는 복잡한 로직을 별도의 클래스</strong>로 도출한다. 가격을 계산하는 알고리즘을 처리하기 위해 클래스를 만들고 새로운 트렌드를 분석하는 Compute Future Trends 클래스를 추가해 4개의 컨트롤 클래스를 식별한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/727411df-5bd1-4c06-bd94-414babbb6498/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW 공학 및 테스팅(5) - OOC(Object-Oriented Concepts)]]></title>
            <link>https://velog.io/@woong_crouch/SW-%EA%B3%B5%ED%95%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8C%855</link>
            <guid>https://velog.io/@woong_crouch/SW-%EA%B3%B5%ED%95%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8C%855</guid>
            <pubDate>Wed, 25 Mar 2026 01:21:21 GMT</pubDate>
            <description><![CDATA[<h1 id="object-oriented-concept">Object-Oriented Concept</h1>
<h2 id="class-concept">Class Concept</h2>
<p>클래스는 캡슐화 되어 구성되며, Interface와 Body로 나눠져있다.</p>
<ul>
<li><strong>Interface</strong>
Interface는 보여지는 영역으로 서비스를 제공하는 다소 추상적인 영역이다. </li>
<li><strong>Body</strong>
Body는 Interface와 달리 숨겨져있으며 object의 기능을 구현해둔 요소를 말한다.</li>
</ul>
<p>이 때, <strong>캡슐화(Encapsulation)는 interface와 body를 구분해서 불필요한 정보를 외부에 노출하지 않는 것</strong>을 말한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/b4d56a1c-fc31-4870-80d4-bfdf3ee4a0a4/image.png" alt=""></p>
<h2 id="default-constructor">Default Constructor</h2>
<p><strong>arguments를 가지지 않는 Constructor</strong>를 말한다.</p>
<p>만약에 <strong>Class가 Constructor를 가지지 않는다면 시스템은 자동적으로 Default Constructor를 제공</strong>한다. C++에서 Class의 다른 Constructor가 존재한다면 자동적으로 만들어주지 않기 때문에, Array를 재정의할 때 에러가 발생한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/52b8a02b-a834-4b8d-bb94-0b00deab8484/image.png" alt=""></p>
<p>명시적 선언이 필수적인 이유는 만약 개발자가 특정 값을 넣기 위해 파라미터가 있는 <strong>Constructor를 만들게 되면, 시스템은 더 이상 Default Constructor를 만들어주지 않는다.</strong></p>
<h2 id="inheritance-concept">Inheritance Concept</h2>
<p>상속은 클래스 간의 관계를 정의할 때, 가장 핵심이 되는 개념이다. 상속은 기존 브모 클래스의 특성을 자식 클래스가 그대로 물려받아 새로운 클래스를 만드는 매커니즘이다. </p>
<p>상속의 가장 큰 목적은 코드의 중복을 피하고 재사용성을 극대화하여 효율적인 코드 관리를 하기 위함입니다. </p>
<h3 id="클래스-중복-관리-및-재사용">클래스 중복 관리 및 재사용</h3>
<p><code>부모 클래스</code>는 Base Class, Parents, Super Class 등으로 불리고, <code>자식 클래스</code>는 Derived Class, Child, Sub class로 불린다. </p>
<p>새로운 클래스는 이미 존재하는 클래스의 모든 <strong>정보를 재사용</strong>하면서 <strong>새로운 정보를 추가하거나 이미 존재하는 정보를 수정</strong>할 수 있다.</p>
<h3 id="서브-클래스의-생성">서브 클래스의 생성</h3>
<p>서브 클래스의 객체가 생성될 때, 부모 클래스의 데이터도 함께 초기화 되어야하므로, <strong>생성자에서 부모 클래스의 초기화(super)를 호출하는 과정</strong>을 말한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/badcc01b-5be8-4c6f-a64e-8cd9c533697e/image.png" alt="">
절차에 대해서 알아보면, <strong>1) 부모와 자식 클래스 모두에 데이터를 입력</strong>한다. 그 다음 <strong>2) 생성자를 호출하여 객체를 생성해 부모/자식 클래스를 모두 초기화</strong>한다. 또한 자식 클래스의 생성자의 초기화 목록에서 부모 클래스의 생성자를 호출한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e67c915e-2c9b-41b9-911c-68231fa01392/image.png" alt=""></p>
<h3 id="타입-변환">타입 변환</h3>
<p>상속에서 파생되는 아주 중요한 요소인 <code>Polymorphism</code>을 곧 배우게 될텐데, 그 바탕이 되는 규칙으로 <strong>부모 클래스가 요구되는 변수 자리에 자식 클래스의 객체가 대신 들어갈 수 있다는 것</strong>이다.</p>
<p>말 그대로 자식은 부모 대신 자식 클래스가 적용되는 것은 가능하지만, 부모는 자식 대신 적용될 수 없다는 것이다.</p>
<h2 id="overriding--polymorphism">Overriding &amp; Polymorphism</h2>
<h3 id="overriding">Overriding</h3>
<p>오버라이딩은 <strong>부모 클래스로부터 상속받은 메서드를 자식 클래스의 목적에 맞게 재정의하는 기법</strong>이다. 총 3가지 목적으로 오버라이딩을 진행할 수 있는데, 각각 확장, 적응, 최적화이다.</p>
<h4 id="확장extension">확장(Extension)</h4>
<p><strong>부모 클래스의 기존 행위를 그대로 유지하면서, 자식 클래스만의 추가적인 동작을 덧붙일 때 사용</strong>한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/e9150ee3-96aa-4499-9560-b07ab1878f4a/image.png" alt=""></p>
<p>부모 클래스가 가지는 메서드를 이용하면서 그 메서드에 자식 클래스의 정보를 이용해 추가적인 기능을 확장할 수 있다.</p>
<h4 id="적응adaptation">적응(Adaptation)</h4>
<p>Sub Class의 행동을 명시적으로 나타내기 위해 Super Class의 행동을 재정의한다. 다시 말하면 <strong>부모 클래스의 행위를 자식 클래스의 상황에 맞게 명시적으로 변경해 적용</strong>할 때 사용한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/971246ed-f407-438a-b83e-6a0ea39cf7f1/image.png" alt=""></p>
<h4 id="최적화optimization">최적화(Optimization)</h4>
<p><strong>특정 자식 클래스에 맞춰 퍼포먼스(계산 속도 등)를 극대화하는 알고리즘으로 대체</strong>할 때 사용한다. 성능을 위해 오버라이딩하는 역할이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/ae311346-997c-4f03-8350-54ca04a37288/image.png" alt="">
다소 추상적인 개념이라 이해가 안될 수 있지만, 예를 들어 다각형 면적을 구할 때, 삼각형은 공식이 존재할 때, 이를 overriding해서 성능을 향상시킬 수 있다.</p>
<h3 id="동적-바인딩">동적 바인딩</h3>
<p>동적 바인딩은 <strong>실행 시점에 변수에 할당된 객체를 파악해 객체에 맞는 함수를 동적으로 실행하는 매커니즘</strong>이다. 클래스에 대한 동적 바인딩이 일어나기에, 오버라이딩 된 메소드가 클래스에 맞게 자동으로 선정된다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e968aeac-0f89-4a23-aa3e-34fa872c5ae9/image.png" alt=""></p>
<p>정적 바인딩과는 시점이 다른데, 동적 바인딩은 <code>Run Time</code> 시점이지만 정적 바인딩은 <code>Compile Time</code>에 할당된다.</p>
<h3 id="다형성polymorphism">다형성(Polymorphism)</h3>
<p>Extend, Implement 관계인 다른 클래스의 객체를 부모 클래스나 인터페이스 형식을 변수에 담을 수 있고, Overriding 된 이름이 같은 메소드가 해당 클래스에 맞게 실행되는 것이다. 즉, <strong>코드는 한 줄이지만 상황에 따라 다양한 형태로 해석되고 동작한다</strong>는 뜻이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/782e1560-842f-43bf-a2d6-f37ea0f4a944/image.png" alt=""></p>
<p>여러 종류의 자식 객체들을 각각의 타입으로 관리하지 않고, 부모 타입의 배열로 하나로 묶어 관리한다.</p>
<h2 id="abstract-class--interface">Abstract Class &amp; Interface</h2>
<h3 id="abstract-class">Abstract Class</h3>
<p>하나 이상의 추상 메서드를 가진 클래스이다. 이때 <strong>추상 메서드란 선언만 하고 구현을 안한 메서드</strong>를 말한다.</p>
<p>추상클래스가 존재하는 이유는 <strong>다형성 코드를 만들기 위해서이다.</strong> 여러 자식 클래스를 하나로 묶어 효율적으로 관리하려면 부모클래스의 배열을 만들어야 한다.</p>
<h4 id="concrete-class">Concrete Class</h4>
<p><strong>모든 동작을 구현한 클래스로 객체</strong>를 가진다. 실질적으로 Abstract와 완전히 반대되는 개념이다.</p>
<h3 id="인터페이스의-개념">인터페이스의 개념</h3>
<p>Interface는 <strong>포함된 모든 메서드가 구현부가 없는 추상 메서드로 이뤄진 극단적인 추상 클래스</strong>를 말한다. 일반적인 변수는 가지지 않는다. Interface는 항상 public, abstract이므로 별도로 public, abstract로 선언할 필요 없다.
<img src="blob:https://velog.io/c2e4eb85-526b-459d-a00a-94a34f844ee0" alt="업로드중.."></p>
<p>Java에서 <strong>다중 상속(부모가 여러명인 경우)은 금지</strong>하지만, 클래스가 하나의 부모를 상속받으며 <strong>여러 인터페이스를 동시에 다중으로 구현하는 것은 허용</strong>된다.</p>
<p>둘 이상의 인터페이스를 구현하려면 클래스 선언에서 implements 키워드 뒤에 쉼표로 구분된 인터페이스 이름 목록을 사용한다.
<img src="blob:https://velog.io/3b5bf871-b155-4b0f-a1bd-52a74e37a682" alt="업로드중.."></p>
<h3 id="인터페이스-사용">인터페이스 사용</h3>
<p>다른 클래스간 Communication 과정에서 사용되고, 오직 추상적 명령으로만 이루어지고 컴포넌트를 연결할 때 사용된다. </p>
<p><img src="blob:https://velog.io/6deaf7fc-13a7-4faa-85db-dd66212ff780" alt="업로드중.."></p>
<p><strong>Strong Coupling은 Concrete Class를 가르키는 연결</strong>을 말하고, <strong>Weak Coupling은 Abstract Class나 Interface를 가르키는 연결</strong>을 말한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW 공학 및 테스팅 (4) - Architecture Design]]></title>
            <link>https://velog.io/@woong_crouch/SW-%EA%B3%B5%ED%95%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8C%85</link>
            <guid>https://velog.io/@woong_crouch/SW-%EA%B3%B5%ED%95%99-%EB%B0%8F-%ED%85%8C%EC%8A%A4%ED%8C%85</guid>
            <pubDate>Wed, 25 Mar 2026 00:21:40 GMT</pubDate>
            <description><![CDATA[<h1 id="architectural-design">Architectural Design</h1>
<h2 id="introduction">Introduction</h2>
<p>요구사항 명세가 완벽하게 정의되었다면, 이후에는 무엇을 해야할까?</p>
<p>Use Case는 입력에 따른 반응을 기반으로 한 기술이다. 시스템의 내부는 요구사항 명세가 명확해져도 <strong>블랙박스</strong>의 형태를 가진다. 고로 개발자인 <strong>우리는 블랙박스를 화이트박스로 바꾸는 절차</strong>를 거쳐야 하고, 이를 위해 설계(architecture)를 해야한다.</p>
<h3 id="architectural-design이란">Architectural Design이란?</h3>
<p>아키텍쳐 디자인은 <strong>Software System이 어떻게 구성되는지 이해하고 그 System의 구조를 전체적으로 디자인하는 것</strong>을 말한다. 개발 요구사항과 디자인 사이에서 중요한 역할을 하며, 시스템의 <strong>주요 구조적 구성요소와 관계 사이에서 정의</strong>한다. </p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/5b1514af-5c8d-4d53-b302-99f2947ad624/image.png" alt=""></p>
<p>시스템의 세가지 핵심은 <strong>1) 기능 (요구 분석에서 결정)</strong>, <strong>2) 구조 (아키텍처 디자인, 클래스 다이어그램)</strong> , <strong>3) 행위 (시퀀스 다이어그램, State 다이어그램)</strong> 으로 정의할 수 있다.</p>
<p>설계는 <strong>Top-Down 방식</strong>으로 진행되고, 점점 세분화되게 설계한다. 컴포넌트를 구성하면서 구조가 짜이면 각 컴포넌트 간의 행위를 정의한다. 아키텍처 디자인은 <strong>디자인과 요구 엔지니어링 사이를 연결하는 &#39;링크&#39;</strong>이고, 아키텍처 디자인의 장점은 <strong>이해 당사자 사이의 소통을 쉽게</strong>해주고 <strong>큰 규모의 재사용</strong>이 가능하며, <strong>시스템 분석이 쉬워지는 장점</strong>을 가진다.</p>
<h2 id="architectural-patterns">Architectural Patterns</h2>
<p>시스템이 서로 통신하는 구성 요소들의 집합으로 어떻게 구성되는지 설명한다. 이러한 아키텍처를 명시적으로 설계함에 있어서 장점은 아래와 같다. <strong>아키텍처 패턴은 지식을 표현하고 공유하고 재사용하는 일종의 수단</strong>이다. 다양한 환경에서 시도되며 <strong>디자인 관행을 양식화해서 설명</strong>한 것으로 볼 수 있다. 주로 이런 <strong>Pattern은 표나 그래프의 형식</strong>으로 표현한다.</p>
<h3 id="mvc">MVC</h3>
<p>MVC 패턴은 Software 디자인 패턴의 일종으로 <strong>Model, View, Controller</strong>로 분리하여 유지보수성과 확장성을 높이는 방식을 말한다.</p>
<p>간단한 구조 형태로 정의된 이 패턴의 로직은 User가 Controller를 통해서 조작을 하면 Model을 통해서 데이터를 가지요고 View가 그 정보를 바탕으로 시각적인 요소로 User에게 전달한다. 간결하게 보자면 아래와 같은 구조로 형성된다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/d0af7187-85d7-43e5-b432-c608b9a002c3/image.png" alt=""></p>
<p>MVC 패턴은 시스템 데이터의 상호작용과 presentation을 분리한다. MVC의 장점은 데이터와 표현 방식 간의 독립적인 변화를 허용하고 그 반대의 경우도 가능하다는 것이다. 모델의 <strong>데이터가 변화하면 여러 뷰에 동시에 업데이트가 가능</strong>해 GUI 기반 시스템이나 웹 애플리케이션에서는 거의 표준처럼 사용된다.</p>
<h3 id="layered-architecture">Layered Architecture</h3>
<p><strong>시스템을 여러 계층으로 구성</strong>하고, <strong>하위 계층이 바로 위 상위 계층에 코어 서비스를 제공하는 구조</strong>이다. 시스템은 최하위 계층부터 서비스를 제공하는 구조까지 계층이 구성되어있다. 계층적인 구조답게 <strong>interface가 변경되면 인접 계층에만 영향</strong>을 미친다. interface에서 여러 계층을 통해 최하위 계층에 존재하는 OS, DataBase까지 계층을 구성해서 운영한다
<img src="https://velog.velcdn.com/images/woong_crouch/post/fab0ae95-f387-474a-8099-850de3e0cbd4/image.png" alt=""></p>
<p><strong>기존 시스템 위에 새로운 기능을 구축</strong>하거나 여러 팀에 개발이 분산되고 <strong>각 팀이 하나의 계층을 책임지는 경우에 주로 사용</strong>하며, 장점으로 <strong>인터페이스가 유지되면 전체 계층의 교체가 가능</strong>하고 <strong>각 계층에 중복 기능을 제공</strong>할 수 있다.</p>
<p>가장 단순한 방식인 만큼 단점도 명확히 존재하는데, <strong>첫번째로 층간분리가 명확하게 발생하지 않는다</strong>는 점이다. 이에 대한 구현의 난이도 또한 높다. 둘째로 <strong>서비스의 요청에 따라 해석 단계가 여러 차례 존재하기에 성능 문제가 발생</strong>할 수 있다. 이로 인해 불필요한 계층간 이동이 발생하여 성능저하가 발생하게 된다.</p>
<h3 id="repository-architecture">Repository Architecture</h3>
<p>모든 데이터가 중앙 저장소에 관리되며, 시스템의 서브 컴포넌트들은 서로 직접 통신하지 않고 <strong>오직 중앙 저장소를 거쳐 데이터를 주고 받는다.</strong></p>
<p>데이터를 교환하는 일종의 보조 시스템의 역할을 담당한다. Repository는 2가지 일을 수행하는데 그 일들은 아래와 같다. 첫째로 <strong>공유 데이터는 중앙 DB 또는 repository에 저장</strong>되며, <strong>모든 하위 시스템에서 접근</strong>할 수 있습니다. 둘째로 <strong>각 하위 시스템은 자체 데이터베이스를 유지</strong>하고 데이터를 다른 하위 시스템에 전달한다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e76a0690-68de-402d-bac0-32d6c125e1ee/image.png" alt=""></p>
<p><strong>장기간 대량 정보가 생성되는 시스템에서 주로 사용</strong>하고, <strong>컴포넌트가 모두 독립적이어서 개발하기 편하고 데이터를 일관성 있게 관리할 수 있다</strong>는 장점이 있지만, <strong>저장소가 문제가 생기면 전체 시스템에 문제가 생긴다는 점</strong>과 <strong>모든 통신을 저장소를 통해 구성하는 것이 비효율적인</strong> 단점이 존재하기도 한다.</p>
<h3 id="client-server-architecture">Client-Server Architecture</h3>
<p>독립적인 특정 서비스를 제공하는 <strong>&#39;서버&#39;의 집합과 네트워크를 통해 서버들에 접속하는 서비스</strong>를 이용하는 &#39;클라이언트&#39; 집합으로 분산된 모델이다. 서버 1개와 다수 클라이언트가 소통하는 구조로, 여러 컴포넌트에 걸쳐 분산을 보이는 분산시스템의 모델이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/6be6a95e-7352-49c9-b599-04130599f6ed/image.png" alt=""></p>
<p>주로 <strong>공유 DB의 데이터를 다양한 위치에서 접근할 때 사용</strong>하고, 시스템의 <strong>부하가 가변적일 때에도 적용</strong>할 수 있다. 서버를 네트워크 상에 분산시키거나 복제해 부하를 조절할 수 있다. 하지만 시스템의 성능이 네트워크 상태에 의존하기에 예측이 어렵고 특정 <strong>서버가 다운되거나 DoS공격을 받게되면, 서비스가 중단될 위험</strong>이 있다.</p>
<h3 id="pipe-and-filter-architecture">Pipe And Filter Architecture</h3>
<p>우리가 흔히 아는 <strong>Unix Shell</strong>이 이 Pipe and filter 구조로 만들어졌다. <strong>입력 데이터를 각 컴포넌트(필터)가 한가지 형태의 데이터 변환으로 처리한 이후 Pipe를 통해 다음 컴포넌트로 넘겨주는 구조</strong>이다. interactive한 시스템에는 적합하지 않지만 순차적으로 처리하는 경우에는 주로 사용할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/e262fe19-cb91-44e1-addd-7ad3adc2e024/image.png" alt=""></p>
<p>하나의 컴포넌트에서 다른 컴포넌트로의 데이터 흐름을 말한다. 주로 흔히 <strong>데이터 처리 기반 애플리케이션에서 사용</strong>된다. 하지만 데이터 전송 형식은 통신하는 변환 간에 합의되야한다는 점이 필요하다.(우리는 이것을 프로토콜이라고 부른다)</p>
<p>워크플로우 비즈니스 프로세스에 적합하며, 변환 단계들이 <strong>병렬 처리(Parallelism)가 가능해 효율을 크게 높일</strong> 수 있다. 다만 컴포넌트 간에 호환되는 <strong>데이터 포맷을 맞춰야하는 오버헤드가 발생</strong>한다.</p>
<h2 id="application-architecture">Application Architecture</h2>
<p>도메인마다 사용하는 어플리케이션 구조가 비슷해 이를 정리한 구조이다. 주로 조직의 요구사항을 충족하도록 설계한다. 비슷한 구조를 중심으로 <strong>특정 요구사항을 충족하는 시스템을 구축하기 위해 구성 및 적용할 수 있는 SW System 유형의 아키텍처</strong>이다. 크게 두가지의 종류로 표현된다.</p>
<h3 id="transaction-processing-systems">Transaction processing systems</h3>
<p>우리가 흔히 아는 웹 정보 시스템(전자상거래, 예약 시스템, ATM 등)으로, 주로 <strong>데이터베이스와의 상호작용</strong>을 다룬다.</p>
<p>가장 밑에 DB가 깔리고, 그 위에 비즈니스 로직, UI가 올라가는 형태를 취한다. 데이터베이스에서 정보를 검색하거나 데이터베이스를 업데이트하려는 <strong>사용자의 비동기적 요청을 처리</strong>한다.</p>
<p><strong>Information System Architecture</strong>
정보 시스템은 <strong>계층형 아키텍처로 구성될 수 있는 보편적인 아키텍처</strong>이다. 계층에는 사용자 인터페이스, 사용자 통신, 정보 검색, 시스템 데이터베이스를 포함한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/f919c1ea-305e-4e10-9462-87e5e5403013/image.png" alt=""></p>
<h3 id="language-processing-system">Language processing system</h3>
<p><strong>기계어나 자연어를 입력받아 다른 표현으로 변환하는 시스템</strong>을 말한다. 우리가 흔히 생각하는 <strong>컴파일러, 인터프리터</strong>가 이 시스템에 포함된다. </p>
<p>컴파일러의 경우 아키텍처가 방식에 따라 여러개로 나뉘고, 이전에 Architecture Pattern에서 보였던 기법들을 주로 사용한다. (pipe-and-filter , repository 등)</p>
<p>오늘은 Architecture Pattern에 대해서 알아보았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WebSocket 통신 방식에 대해서]]></title>
            <link>https://velog.io/@woong_crouch/WebSocket-%ED%86%B5%EC%8B%A0-%EB%B0%A9%EC%8B%9D%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</link>
            <guid>https://velog.io/@woong_crouch/WebSocket-%ED%86%B5%EC%8B%A0-%EB%B0%A9%EC%8B%9D%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</guid>
            <pubDate>Mon, 23 Mar 2026 15:58:10 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며..</h2>
<p>주식 예측 프로그램을 동기들과 제작해보는 프로젝트를 진행 중에, 주식 그래프를 구현하면서 몇 가지 이슈에 부딪혔다. 초기엔 BackEnd에서 구현해본 것이 REST API가 대부분이라 당연히 방향성을 그렇게 잡고 움직였다.</p>
<p>하지만 프론트를 조금 구현하던 중 정보를 받아오는 것이 REST API로 진행하면 매끄럽지 않다는 것을 인지했다. 이러한 문제를 해결하고자 방법을 찾다가 <code>WebSocket</code>을 찾았고, 우리는 공부를 위해 REST와 <code>Websocket</code>을 모두 구현해보고자 한다.</p>
<p>그러기 위해서는 <code>WebSocket</code>에 대한 공부가 필요했고, 공부한 내용을 이렇게 블로그에 정리해보았다.</p>
<h2 id="rest-api-와-websocket">REST API 와 WebSocket</h2>
<p><code>REST API</code>와 <code>WebSocket</code>의 차이를 알아보려면 REST API가 가지는 한계를 알아봐야한다. REST API는 아래와 같은 한계를 가진다.</p>
<ul>
<li><strong>요청이 반드시 필요하다.</strong></li>
<li><strong>응답을 받으면 바로 연결을 끊어버려서 다시 요청을 보내야 통신이 가능하다.</strong></li>
<li><strong>정보를 전송할때마다 HandShake를 진행한다.</strong></li>
</ul>
<p>이러한 한계들은 결국 데이터를 빠르게 받아오고 빠르게 처리하는 과정이 필요한 서비스에는 너무도 비효율적인 방식이 되었고, 결국 <code>WebSocket</code>이 탄생하여 오늘날 사용되게 되었다.</p>
<h2 id="code로-보는-websocket">Code로 보는 WebSocket</h2>
<p>그렇다면 코드로는 어떻게 구현해볼 수 있을까. 내가 자주 사용하는 Spring Boot를 이용해서 이 WebSocket 기술을 구현해보자.</p>
<h3 id="controller">Controller</h3>
<pre><code>@Controller
public class StockController {

    private final StockService stockService;
    private final SimpMessagingTemplate messagingTemplate; 

    public StockController(StockService stockService, SimpMessagingTemplate messagingTemplate) {
        this.stockService = stockService;
        this.messagingTemplate = messagingTemplate;
    }

    // React에서 &#39;/app/subscribe&#39; 로 메시지를 보낼 때 실행됨
    @MessageMapping(&quot;/subscribe&quot;) 
    public void handleSubscribe(@Payload Map&lt;String, String&gt; payload) {
        String symbol = payload.get(&quot;symbol&quot;);
        Object currentStockData = stockService.getCurrentPrice(symbol); 
        messagingTemplate.convertAndSend(&quot;/topic/stock/&quot; + symbol, currentStockData);
    }
}</code></pre><p>위 코드는 개략적인 코드를 가져왔다.</p>
<p><code>WebSocket</code>을 본격적으로 작업하려면 <strong>Topic(Room)</strong>이라는 개념을 이해해야한다. 웹소캣을 통해 주식 데이터를 받아오면 API를 통해 모든 주식 정보를 다 받아오게 된다. 만약 방이 없다면 이러한 정보들을 처리하지 못하고 받아내면서 브라우저에 강한 무리를 주게 된다.</p>
<p>이를 방지하기 위해 우리는 각 주식에 맞게 &quot;Room&quot;을 나누어서 처리한다. 그러면 사용자(User)는 방을 골라서 본인이 원하는 정보를 담은 Room에 대한 정보를 얻는 것이다. 이 과정을 우리는 <strong>Subscribe(구독)</strong>이라고 한다.</p>
<p>그리고 여기서 우리는 <strong>SimpMessagingTemplate</strong>을 주요하게 봐야한다. 이 항목은 이 <code>WebSocket</code>에서 정보를 알려주는 확성기의 역할을 한다. 이 확성기는 모두를 향해 제공되지만 이를 Room을 나누고 구독을 함으로서 각각의 방에, 각각의 User에게 원하는 데이터를 전송해주는 것이다.</p>
<p>이 코드는 아주 예시이기에 현재 가격을 가져오고, Room을 나눠서 특정 Room의 사용자들에게 값이 전달되는 기능만을 가지는 Controller이다.</p>
<h3 id="service">Service</h3>
<pre><code>@Service
public class StockService {

    private final Random random = new Random();
    private double lastClose = 75000;

    public StockPrice getLatestPrice(String symbol) {
        double open  = lastClose + (random.nextDouble() * 400 - 200);
        double close = open      + (random.nextDouble() * 1000 - 500);
        double high  = Math.max(open, close) + random.nextDouble() * 300;
        double low   = Math.min(open, close) - random.nextDouble() * 300;
        lastClose = close;

        return new StockPrice(
                symbol,
                (long) open,
                (long) high,
                (long) low,
                (long) close,
                Instant.now().getEpochSecond()
        );
    }
}</code></pre><p>Service는 받아내는 정보에 맞게 수정해야한다. 지금은 임시로 시가, 종가, 고가, 저가를 중심으로 나누어서 작업을 하도록 구성해두었다.</p>
<p><del>사실 WebSocket 구현 자체와는 크게 중요한 내용이라고 보이진 않는다. 차후 기능이 추가되면 더 자주 사용될 것이다.</del></p>
<h3 id="scheduler">Scheduler</h3>
<pre><code>@Component
public class StockScheduler {

    private final SimpMessagingTemplate messagingTemplate;
    private final StockService stockService;

    public StockScheduler(SimpMessagingTemplate messagingTemplate, StockService stockService) {
        this.messagingTemplate = messagingTemplate;
        this.stockService = stockService;
    }

    @Scheduled(fixedDelay = 1000)
    public void pushStockPrices() {
        StockPrice price = stockService.getLatestPrice(&quot;005930&quot;);
        messagingTemplate.convertAndSend(&quot;/topic/stock/005930&quot;, price);
    }
}</code></pre><p>우리는 여기서 특정 종목에 대한 dto를 받아와서 messagingTemplate로 정의된 확성기를 통해 /topic/stock/{stockId} 라는 Room으로 내용을 쏴주는 절차를 밟는다. 1000ms로 작업을 해두었기에 1초마다 새로운 봉차트를 그리는 방향으로 디자인된다. Scheduler가 가지는 가장 중요한 요소는 <strong>1초마다 정보를 보내준다는 것</strong>이다.</p>
<p>사실상 front-End로 가기위해서는 <code>Scheduler</code>는 필수적인 요소이라고 볼 수 있다.</p>
<h2 id="summary">Summary</h2>
<p>전체적인 플로우는 위의 사진과 같이 이해하면 될 것 같다. 전체적인 플로우를 이해하고 코드를 들여다 보면 더 쉽게 느껴지지 않을까 싶다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/249c9f52-8c34-4287-a3fd-20cd8c120c12/image.png" alt=""></p>
<p>물론 기능적으로 앞으로 더 맞춰나갈 것이 많으리라 보지만, 당장 처음 배운 개념과 기술에 대해서 너무 많은 것을 한번에 하기보다는, 하나씩 배워나가며 개념을 정립하고 이를 확장해서 더 좋은 기능들을 추가해 나가는 방향의 작업도 좋지 않을까.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PM으로서의 첫걸음]]></title>
            <link>https://velog.io/@woong_crouch/PM%EC%9C%BC%EB%A1%9C%EC%84%9C%EC%9D%98-%EC%B2%AB%EA%B1%B8%EC%9D%8C</link>
            <guid>https://velog.io/@woong_crouch/PM%EC%9C%BC%EB%A1%9C%EC%84%9C%EC%9D%98-%EC%B2%AB%EA%B1%B8%EC%9D%8C</guid>
            <pubDate>Mon, 23 Mar 2026 14:24:55 GMT</pubDate>
            <description><![CDATA[<p>대학교를 들어와서부터 나는 창업에 관심이 많았고, 자연스레 동기들과 프로젝트에서 팀리더의 역할을 맡아왔다.</p>
<p>내가 이끄는 것을 좋아해서인지 이끌다보니 좋아진 것인지는 모르지만, 어렸을 때부터 이러한 리더의 역할을 동경하고 지향해 왔다는 것에는 이유가 있지 않을까.
3학년이 된 지금, 나는 많은 프로젝트를 해보고 이끌어보고자 한다. 지금 진행 중인 프로젝트들도 많고 이 프로젝트에서 나의 역할을 다양하다. Front-end, Back-end 등 여러 파티션에서 경험을 쌓아가는 중이다. 그리고 이러한 경험이 충분한 밑거름이 된다고 생각하고 나는 천천히 이끌어 나갈 것이다.</p>
<p>IT 업계에서 PM으로의 길을 조금씩 나아가보고자 한다.</p>
<h2 id="product-manager">Product Manager</h2>
<p>우선 Product Manager이란, Product(제품)을 Manage(관리)한다는 아주 간단한 뜻풀이로 접근할 수 있다. 
그렇다면 그냥 아이디어 내는 기획자랑 비슷한가? 그렇게 묻는다면 크나큰 오산이다. 보편적으로 PM은 <strong>제품을 출시하고 유지보수하기까지의 전반을 운영 하는 것</strong>에 중심을 둔다. 아무래도 운영을 한다는 지점에서 이 직군은 경력이 있어야 주로 도달한다는 특징을 가지기도 한다. 왜 경력이 있어야 PM을 할 수 있는 것인가? 그래야만 이 시스템 전반에 대해서 알 수 있기 때문이다.</p>
<p>자연스레 대학생인 내가 왜 <code>PM</code>을 꿈꾸는지를 궁금해할 수 있다. 그건 다음에 또 다른 포스트로 적어보겠다.</p>
<p><code>PM</code>의 가장 주요한 역할은 &quot;기획문서 작성&quot;이다. 그렇다면 기획 문서는 무엇일까.</p>
<h2 id="기획문서">기획문서</h2>
<p>기획문서는 하나의 서비스를 만들 때, 필요한 내용을 정리하고 효율적인 소통을 위해 정의해두는 명세서와 같은 문서들의 집합이라고 볼 수 있다.</p>
<p>그렇다면 어떤 기획문서를 작성해야할까?</p>
<h3 id="ia">IA</h3>
<p>IA, <code>Information Architecture</code>의 줄임말인 IA는 서비스의 정보와 계층적 구조에 대해서 보여준다. 서비스가 어떻게 구성되는지를 기준으로 하는 네비게이션 체계를 설계하는 것이 중심이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/0f7b7ea3-905c-4ee1-9419-f8442197e4a0/image.png" alt=""></p>
<h3 id="api-명세서">API 명세서</h3>
<p>사실상 개발자와의 협업에 가장 깊게 중심을 둔 지점이다. 개발에 있어서 API 명세서는 필수적이다. 명세서를 디자인하지 않고 진행하게 되면 협업 자체가 굉장히 버거워진다. 그래서 최대한 명확하게 필요한 정보를 작성하는 것이 중요하다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/9c4f497f-0ef1-4d7b-b3df-406c1535e3ba/image.png" alt=""></p>
<h3 id="erd">ERD</h3>
<p>API 명세서와 더불어 백엔드 개발자의 중추와도 같은 요소로, 데이터베이스 구조를 작성하는 것이다. 데이터가 많이 필요한 서비스일수록 이 ERD의 구조에 따라 프로그램의 성능이 격하게 차이난다. 고로 ERD 작성을 하는 것에 힘을 많이 들여야한다.
<img src="blob:https://velog.io/c32e39fd-bf5f-4b7d-a9e6-8146eca6e97f" alt="업로드중.."></p>
<h3 id="prd">PRD</h3>
<p>사실상 이 모든 내용의 개요가 될 문서이다. 요구사항 정의서라고 불리는 이 문서의 작업을 통해 프로젝트의 방향성을 명확하게 드러낸다. 개요서나 계획서와도 같은 결을 가지고 있다고 볼 수 있는 문서로, PM으로서 작성해야하는 중요 문서 중 하나이다.</p>
<h2 id="마치며">마치며..</h2>
<p>프로젝트를 진행하면서 이외에도 다양한 기획 문서를 적용할 수 있고, 그런 다양한 기획문서를 이용해서 더 좋은 설계를 할 수 있다. 
여러 프로젝트를 거치며 PM의 역할이 중요하고 선제적인 문서작업, 기획 단계가 탄탄할수록 프로젝트가 순항한다는 것을 알게 되었고 이를 위해서 꾸준히 공부하고 다져나가고자 한다.</p>
<p>첫 포스트는 이정도로 마무리 하고자한다. 앞으로는 더 좋은 글을 써나갈 수 있기를 바라며..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Software Engineering & Testing(3) - 방법론 & 요구사항 분석]]></title>
            <link>https://velog.io/@woong_crouch/Software-Engineering-Testing</link>
            <guid>https://velog.io/@woong_crouch/Software-Engineering-Testing</guid>
            <pubDate>Wed, 18 Mar 2026 00:27:22 GMT</pubDate>
            <description><![CDATA[<h1 id="sw-개발-방법론">SW 개발 방법론</h1>
<h2 id="sw-개발-방법론-개요">SW 개발 방법론 개요</h2>
<h3 id="sw-개발-방법론이란">SW 개발 방법론이란?</h3>
<p>소프트웨어 시스템을 개발하는데 필요한 일련의 활동을 우리는 <strong>&quot;소프트웨어 프로세스&quot;</strong> 라고 부른다. 이는 아래와 같은 요소로 구성된다.</p>
<ul>
<li><strong>명세</strong> : 시스템이 무엇을 해야하는지 정의한다.</li>
<li><strong>설계 및 구현</strong> : 시스템의 조직을 정의하고 시스템을 구현한다.</li>
<li><strong>테스팅</strong> : 고객이 원하는 것을 수행하는지 확인한다.</li>
<li><strong>유지보수</strong> : 변화하는 고객 요구에 대응해서 시스템을 변화시킨다.</li>
</ul>
<p>소프트웨어 프로세스 모델. 즉, <strong>개발방법론은 프로세스의 추상적인 표현</strong>이다. 특정 관점에서 프로세스에 대한 설명을 제공하는 것을 말한다.</p>
<h3 id="sw-개발-방법론의-비교-포인트">SW 개발 방법론의 비교 포인트</h3>
<p>현재 SW 산업에서는 여러 개발 방법론이 존재한다. 우리는 이 방법론들을 비교해보고 적절한 방법론을 사용해야하는데, 아래의 기준을 통해 비교를 할 수 있다.</p>
<ul>
<li><strong>주요 활동의 반복성</strong> : 주요 활동을 반복하는지, 그리고 얼마나 자주 하는지를 고려해야한다.</li>
<li><strong>수행가능 버전(MVP)의 출시 기간</strong> : 수행가능한 버전인 MVP가 언제 나오는가에 대해 고려해야한다.</li>
<li><strong>요구변경 수용</strong> : 요구사항 변경이 들어오면 이를 얼마나 대응할 수 있는가를 고려해야한다.</li>
<li><strong>개발 스케줄 관리 수월성</strong> : 개발 일정을 얼마나 가시적으로 드러내는지 고려해야한다.</li>
</ul>
<p>요즘과 같은 시대에는 AI의 역할이 크게 대두되는 추세인데, AI에게 일을 잘 시키기 위해서는 프롬프트를 잘 전달해줘야 한다. 이러한 AI 시대에 어떤 식으로 필요한 인력이 되어 스토리를 풀어나갈 것인지 생각해봐야 한다.</p>
<h2 id="sw-개발-방법론의-종류">SW 개발 방법론의 종류</h2>
<h3 id="1waterfall-모델">1.Waterfall 모델</h3>
<p>Waterfall 모델은 위 그림처럼, 명확하고 순차적인 단계를 지닌다. 프로젝트가 시작해서 문제분석, 요구사항 명세 등을 거쳐 <strong>구현까지의 로직이 순차적으로 존재한다는 것</strong>이 특징이다. </p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/eab86be7-6f37-4030-806d-92a15701fa4b/image.png" alt=""> waterfall 모델의 로직</th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/fd5d8df4-7c6d-41bd-bed8-bfa75c94fb8c/image.png" alt=""> waterfall의 비유연성</th>
</tr>
</thead>
</table>
<p>이러한 순차적 구조는 가장 치명적인 문제를 가지는데, 바로 <strong>비유연성</strong> 이다. 중간 절차에 대한 변경사항이 존재할 때, 이를 수행하는 것이 어렵다는 것이다. 이러한 점이 문제를 크게 발생시킨다.</p>
<p>이러한 Waterfall 모델은 <strong>요구사항이 명확한 경우</strong>에만 적용하기에 적합하다. 그래서 보통 Critical Project, <strong>즉 국방과 같은 분야에서는 문서화와 인증이 필수적이므로 장기 프로젝트</strong>에서는 필연적으로 이 방법론을 선택하게 된다.</p>
<h3 id="2병렬적-개발-방법론">2.병렬적 개발 방법론</h3>
<p>Waterfall 모델이 조금 변형된 스타일로, 같은 구조적 개발 방법론의 축에 들어간다. <strong>계획, 문제 분석, 요구사항 명세는 순차적으로 진행</strong>하고, <strong>이후의 개발은 subproject를 여러개를 동시에 실행시켜서 Prototype을 형성하는 방법론</strong>이다. 이 또한 요구사항이 명확한 경우에만 사용하는 것이 좋다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/f9ba539b-5db0-40cc-a2c1-7853573b6885/image.png" alt=""></p>
<h3 id="3prototyping">3.Prototyping</h3>
<h4 id="진화적-프로토타이핑">진화적 프로토타이핑</h4>
<p><strong>빠르게 prototype을 만드는 것에 중심을 두고 개발하는 방식</strong>이다. 초기 개발 사양을 구성하고 이를 최종 시스템으로 수정 및 보완해서 확장하고 이를 통해 시스템을 개발하는 방식을 말한다. 요구사항이 명확하게 설정되지 않은 경우에 요구사항을 명확하게 하기 위해 사용하는 방법이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/4e898e6d-8ca2-4088-827e-c6a6ae690967/image.png" alt="">
하지만 프로토타이핑 또한 단점이 분명하게 존재하는데, 초기 프로토타입에 래핑을 하는 것이기에 프로젝트가 다소 지저분해질 수 있고, 이 과정에서 복잡성이 증대한다는 것을 볼 수 있다.</p>
<h4 id="throwaway-프로토타이핑">Throwaway 프로토타이핑</h4>
<p>위와 같은 문제를 해결하기 위해, <strong>Waterfall 모델을 적절히 섞은 프로토타이핑</strong>이라고 보면된다. 엄밀히 말하면 프로토타이핑의 목표는 시스템 요구사항을 이해하는 것이라고 볼 수 있다. 우리가 Waterfall 모델을 알아볼 때, 이 방법론은 요구사항이 명확해야한다고 했으니 둘을 잘 섞어본 것이다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/dc9595b8-5996-44e8-b7bd-e2ee0c03d01b/image.png" alt=""></p>
<p>그래서 요구사항이 명확해질때까지 프로토타이핑을 사용하고 이후 Waterfall 모델을 이용해 개발하는 방식을 진행한다. 이를 통해 복잡성이 과도히 증대되는 것을 막을 수 있다.</p>
<p>이러한 <strong>prototyping 방식은 속도에 의미</strong>를 가진다. 대부분의 경우 갑과 을의 관계에서 개발을 진행하고 그러다보니 프로토타입이 빠르게 나올수록 갑의 이해도가 정립되면서 요구사항의 품질이 올라가는 효과를 볼 수 있다.</p>
<h3 id="incremental점진적-개발">Incremental(점진적) 개발</h3>
<p>기능에 대한 increment(증분)을 미리 나누어 두고 개발을 하는 방식을 말하고, 사용자 요구사항에 우선순위를 부여해서 그 순위에 맞춰서 작업하는 방식이다. 해당 요구사항은 고정하고 이후 증분에서 요구사항을 계속 발전시키는 방식이다. 한마디로 <strong>전체 시스템을 필요한 여러 개의 기능 단위인 &#39;증분(Increment)&#39;으로 나누어 순차적으로 개발하는 방식</strong>이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/d7314a6d-5ba3-40ec-99f4-74c95a466b97/image.png" alt=""></p>
<p>기능을 빠르게 제공하고, 실패 위험을 감소시키며 우선순위에 따라 테스트가 많이 발생할 수 있다는 점에서 장점을 가지지만 개발이 빠르게 진행되어 매 버전마다 문서를 수정하는 것이 비효율적일 수 있고, <strong>증분이 추가될 때 구조가 점점 지저분해지는 프로토타이핑의 특성이 단점으로 작용한다.</strong></p>
<p>prototype과 거의 유사하지만 조금 더 체계적인 방식으로 이뤄진다. 그러다보니 위에서 말한 것처럼 prototype의 문제점도 똑같이 가진다. incremental 개발 방법은 객체 지향 개발 방법이고, 그에 따라서 적용되는 분야도 상황에 따라 바뀐다.</p>
<h3 id="unified-process">Unified Process</h3>
<p>Unified Process(UP)는 기존의 구조적 방법론들과 다르게 <strong>객체 지향 방법론의 일종</strong>이다.</p>
<p>Booch Method, Jacobson&#39;s Objectory, OMT라는 방법론을 하나로 합친 방법론이 발표된다. UP는 적응가능한(adaptable) 방법론이다. 즉, <strong>특정 정보 시스템의 특성에 맞게 수정해서 적용하는 방식</strong>이라는 것이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/70cda42b-a4b8-452b-85e5-9bbe7f08dcdf/image.png" alt=""></p>
<h3 id="애자일-방법론">애자일 방법론</h3>
<p>애자일 방법론은 사실상 오늘날 가장 주로 쓰이는 방법론으로 불린다. <strong>단순하고 반복적인 개발을 강조</strong>하며, 아래의 표를 통해 애자일 개발의 원리를 확인할 수 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/97486569-2633-42dd-871a-a1a70016f163/image.png" alt=""></p>
<p>애자일 방법론의 가장 핵심은 &quot;타임 투 마켓&quot;이다. 어떤 프로그램이나 서비스를 출시하고자할 때, <strong>그 서비스의 완성도보다는 출시 시기가 더욱 중요한 요소</strong>이다. 품질이나 완성도를 후순위로 차치한 이후 빠르게 시장에 서비스나 제품을 출시하는 것을 최우선으로 스프린트를 컴팩트하게 가져가는 방법이다. </p>
<h3 id="xpextreme-programming">XP(Extreme Programming)</h3>
<p>XP 방법은 반복적 및 점진적 방법을 이용해 정보 시스템 개발에서 이슈가 되는 새로운 접근법이다.</p>
<p>프로그래머는 먼저 Task에 대한 Test case를 생성해서 자동 테스트 환경을 구성하고 하나의 컴퓨터에서 파트너와 함께 동시 작업한다. 이 모든 테스트 케이스를 올바르게 작동할 때까지 구현하고 이가 마무리되면 끝내는 방식을 택한다. 이때 <strong>한 컴퓨터로 동시에 작업한다는 의미는 한명이 코딩하고 한명은 뒤에서 같이 보면서 작업하는 것</strong>을 말한다.</p>
<p>XP의 방식을 택하려면 기본적으로 <strong>중급 이상의 시니어급 프로그래머</strong>가 되어야한다. 그리고 Customer를 한명 넣어서 운영된다. 로직을 보면 하루 단위로 개발 버전을 수정하고 업데이트를 해 나가고, Customer가 개발 버전을 검증하고 피드백을 주는 방식으로 운영된다. </p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/0d6cb30c-a77d-4bd6-bd9b-d22ef89c2032/image.png" alt=""></p>
<h4 id="ms의-사례">MS의 사례</h4>
<p>우리는 MS를 한번 주목할 필요가 있다. MS는 에러가 발생함에 크게 개이치 않는다. <strong>애자일 방법론의 기조에 맞게 제품을 만들고 시장이 필요로 하는 시점에 완성도가 낮아도 일단 출시</strong>하여 이후 제품을 보강해 나가는 것이다. 이러다보니 MS가 독특한 점이 있는데, 보통은 갑과 을이 존재하는 프로젝트가 대부분이지만 MS의 경우에는 갑이 명확하게 존재하지 않는다. 어찌보면 대중이 그 갑의 위치로 들어갈 수도 있다고 본다. 결론적으로 MS가 가지는 포인트는 <strong>&quot;time to market&quot;</strong>이다.</p>
<p>애자일 방법론은 기존의 방법론들이 절차를 중시하며 흐름을 이어간 것과 다르게 사람을 중심으로 개인의 업무 프로세스를 보장해주는 방법론이다. 에러가 발생하면 수정하고 다시 테스팅하는 과정을 거치며 스프린트를 아주 잘게 쪼개서 업무를 이어간다. 이렇게 이어가다보면 코드가 스파게티 코드가 되고, 이를 정리해주는 것이 <strong>&#39;리팩토링&#39;</strong>이다. 리팩토링을 통해서 기존의 코드를 수정한다. 다만 리팩토링의 특징은 기능을 추가하거나 더 새로운 기술을 넣는 것이 아니라, 서비스 자체는 큰 변화가 없다는 것이다.</p>
<p>나아가 테스팅을 하는 관점에서는 이 방식을 TDD라는 이름으로 이해할 수 있는데 <strong>TDD란 Test-Driven Development</strong>로, 실제 코드를 작성하기 전에 실패하는 단위 테스트를 먼저 작성하고, 이를 통과한 최소한의 코드를 구현해 리팩토링을 반복하는 과정을 말한다.</p>
<h3 id="plan-driven-vs-agile-specification">Plan-driven vs agile specification</h3>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/b879cc87-2cb0-4fc0-b529-79eea5155ee8/image.png" alt=""></p>
<hr>
<br>

<h1 id="요구사항-분석">요구사항 분석</h1>
<h2 id="요구사항-분석의-목표">요구사항 분석의 목표</h2>
<p>요구사항 분석은 제안된 시스템이 무엇을 수행하는지를 정의한 것이며, 어떻게를 정의하는 것은 아니다. 명확히 말하면 <strong>&quot;What&quot;을 정의하는 것</strong>이라 볼 수 있다. <del>어떻게는 설계 단계에서 정의 한다.</del></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/65549e80-1afa-453e-8399-d167b6210b10/image.png" alt=""> </p>
<h2 id="요구사항-명세의-구성요소">요구사항 명세의 구성요소</h2>
<p>요구사항 명세의 구성요소로는 아래의 3가지로 나뉘는데, 앞의 2개는 우리가 흔히 생각하는 요구사항의 명세이다. 무엇을 수행하는지, 어떤 특성을 가지는지 이것은 <strong>프로젝트에서 반드시 다루어야하는 내용</strong>이라고 볼 수 있다. </p>
<p>하지만 그보다 선행되게 생각해야하는 부분이 있는데, 그것이 <strong>도메인의 기본적인 상식</strong>이다. 내가 하고자하는 프로젝트가 포함된 도메인에 대해서 기본적인 지식을 가지지 않으면 큰 어려움을 가질 수 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/b4867a1f-6fa8-4b2c-a2fd-32958cff0ec7/image.png" alt=""></p>
<h3 id="기능적--비기능적-요구사항">기능적 &amp; 비기능적 요구사항</h3>
<p>요구사항은 크게 두가지로 나뉘는데, 기능적 요구사항, 비기능적 요구사항으로 나뉜다.</p>
<h4 id="기능적-요구사항">기능적 요구사항</h4>
<p>기능적 요구사항은 시스템이 제공해야하는 서비스 명세서로 특정 입력이 발생하면 이에 대한 반응을 어떻게 할 것이고, 특정 상황에서 시스템이 어떻게 작동하는지 등의 <strong>서비스의 기능적인 요소를 포함하는 내용</strong>이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/b391f45b-b6f7-42a2-9abc-4e34ea90d076/image.png" alt=""></p>
<h4 id="비기능적-요구사항">비기능적 요구사항</h4>
<p>비기능적 요구사항은 서비스의 기능이 아닌 개발 프로세스의 제약, 표준 등의 시스템이 제공하는 서비스나 기능의 제약사항들을 말하고, 개별 기능이나 특정 컴포넌트가 아닌 <strong>전체 시스템에 적용되는 속성들</strong>을 기술한다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/0c57ee08-0d56-4a8f-897e-5fdec05f39a0/image.png" alt=""></p>
<h2 id="요구사항-명세서-작성법">요구사항 명세서 작성법</h2>
<p>요구사항 명세서는 다음과 같은 방법으로 작성할 수 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/8fba97ee-64db-4527-a23a-3279ea4665f1/image.png" alt=""></p>
<h3 id="자연어-명세">자연어 명세</h3>
<p><strong>자연어 문장으로 명세를 작성하는 방식</strong>을 이야기한다. <strong>가장 직관적이고 표현하기가 용이</strong>하기 때문에 보편적으로 사용하고 고객 또한 요구사항을 쉽게 이해할 수 있다. 하지만 이 표기법은 몇가지 문제점이 존재한다.</p>
<ul>
<li><strong>명확성 부족</strong> : 정확도를 높이면 문서를 읽거나 이해하기가 어려워진다.</li>
<li><strong>요구사항 혼동</strong> : 기능적, 비기능적 요구상항이 혼재되는 경향이 있다.</li>
<li><strong>요구사항 합병</strong> : 여러가지 요구사항을 함께 묶어 하나로 표현할 수 있다.</li>
</ul>
<h3 id="구조적-명세">구조적 명세</h3>
<p>작성자의 표현 자유가 제한되고 요구사항을 표준방식으로 작성하도록 하고 <strong>임베디드 제어 시스템에 대한 요구사항에는 적합</strong>하나 <strong>정보 시스템의 요구사항 작성에는 매우 엄격</strong>하다.</p>
<h3 id="uml-based-system-modeling">UML-based System Modeling</h3>
<p>UML 방식의 장점은 <strong>Customer가 딱 보고 무슨 이야기인지 이해할 수 있다는 점</strong>이다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/91c2cf06-54c5-4866-bf56-e62e939fe59a/image.png" alt=""></p>
<h4 id="use-case-분석">Use Case 분석</h4>
<p><strong>고객 요구사항에 대한 분석, 개발 시스템의 범위를 정의</strong>한 것으로, 요구사항을 그래픽 다이어그램 및 시나리오 방식으로 기술하는 형태다. 시스템 관점에서 외부 상호작용의 적절정을 검증하고 수행 시나리오로서 acceptance test에 활용된다.</p>
<ul>
<li><strong>Use Case</strong>
use case는 actor 관점에서 <strong>관찰 가능한 연속적인 행위의 집합을 기술</strong>한 것이다.</li>
<li><strong>Actor</strong></li>
<li><em>시스템과 상호작용하는 외부 에이전트가 수행하는 역할*</em>을 말하고, 하나의 외부 에이전트가 여러 역할을 수행할 수 있다.</li>
</ul>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/6089780f-8296-4ebc-8c3f-d0563ab80586/image.png" alt=""> Use Case 예시</th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/1261d39b-165b-49d3-9734-81f43fdefadb/image.png" alt=""> Use Case 설명 기술</th>
</tr>
</thead>
</table>
<h4 id="use-case-간의-관계">Use Case 간의 관계</h4>
<p>Use Case 간에는 관계가 존재한다.</p>
<ul>
<li><strong>포함 관계 &lt;&lt; include &gt;&gt;</strong>
여러 Use Case들이 공통적인 행위를 하는 경우, <strong>공통 행위를 따로 나타내고 이를 포함하도록 하는 것</strong>이다.</li>
<li><strong>확장 관계 &lt;&lt; extend &gt;&gt;</strong>
하나의 Use Case의 확장점에서 추가적인 <strong>행위를 추가해 다른 Use Case로 변형한 것</strong>이다.</li>
</ul>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/e79cf752-7331-47cf-a1cf-c7cad6255d6c/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/b2f224a1-9864-4eef-9b14-c60b9c6a4427/image.png" alt=""></th>
</tr>
</thead>
</table>
<h3 id="요구사항-명세서와-테스팅">요구사항 명세서와 테스팅</h3>
<p>요구분석 단계에서 요구사항 명세서에 명시된 <strong>기능적 및 비기능적 요구사항에 대한 Test Plan을 수립</strong>한다. Test Case 작성 과정을 통해 요구사항의 일관성 및 완전성을 검사한다.</p>
<br>
<br>

<p>이번 포스트에서는 여러 방법론들과 요구사항 명세에 대한 부분을 알아보았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Software Engineering & Testing (2) - Project 식별 및 선택]]></title>
            <link>https://velog.io/@woong_crouch/Software-Engineering-Testing-2-Project-%EC%8B%9D%EB%B3%84-%EB%B0%8F-%EC%84%A0%ED%83%9D</link>
            <guid>https://velog.io/@woong_crouch/Software-Engineering-Testing-2-Project-%EC%8B%9D%EB%B3%84-%EB%B0%8F-%EC%84%A0%ED%83%9D</guid>
            <pubDate>Wed, 18 Mar 2026 00:26:11 GMT</pubDate>
            <description><![CDATA[<h2 id="프로젝트는-어떻게-시작하는가">프로젝트는 어떻게 시작하는가?</h2>
<p>프로젝트는 비즈니스 요구사항을 중심으로 진행한다. <strong>프로젝트를 제의한 사람(Sponsor)는 요구사항을 인지하고 구현을 요청</strong>해야한다. 결론적으로 프로젝트에서 <strong><em>비즈니스 요구사항이 가장 중요한 뼈대가 되는 것</em></strong>이다. 이러한 비즈니스 요구사항은 시스템의 기능을 결정하고 이때의 비즈니스 가치가 명확하게 드러나야 한다.</p>
<h2 id="시스템-요구사항system-request">시스템 요구사항(System Request)</h2>
<p>시스템 요구사항(System Request)은 _<strong>프로젝트를 공식적으로 제안하기 위해 작성하는 1~2장 분량의 요약 문서</strong>_이며, 프로젝트에서 가장 중요한 것 중 하나이다. 요구사항에는 아래 5가지 요소를 필수적으로 포함시켜야한다.</p>
<ul>
<li><strong>Project Sponsor</strong>
프로젝트를 구상한 사람이자, 비즈니스적 측면에서 프로젝트의 주요 포인트를 짚어주는 사람이다.</li>
<li><strong>Business need</strong>
시스템을 구상할 때의 비즈니스와 관련된 이유를 나열한 것이다.</li>
<li><strong>Business requirements</strong>
시스템이 제공되었을 때, 비즈니스가 가지는 가능성을 말한다.</li>
<li><strong>Business value</strong>
시스템이 조직에 생성되어 도입되면, 이로 인해 발생하는 이점(이익)을 말한다.</li>
<li><strong>Special issues or constraints</strong>
시스템을 구현과 관련된 문제나 상위 관리자가 내린 결정들을 말한다.</li>
</ul>
<h2 id="예비-프로젝트-승인">예비 프로젝트 승인</h2>
<p>시스템 요구는 상위 관리자의 승인에 따라 작성된다. 제공된 정보를 기반으로 이 프로젝트를 진행하는 것이 메리트가 있는지를 평가한다. *<em>가치있는 프로젝트는 승인(1차)되고, 결과적으로 타당성 분석을 통한 추가적인 검증을 거친다. *</em>이를 통해 정말 실현 가능한지에 대해 파악하게 된다.</p>
<h2 id="타당성-분석-feasibility-analysis">타당성 분석 (Feasibility Analysis)</h2>
<p>제안된 프로젝트에 대한 <strong>기회와 한계를 이해할 수 있는 요소</strong>이다. <strong>프로젝트의 디테일한 비즈니스 케이스를 검증하며 프로젝트가 진행되는 내내 평가</strong>된다. 타당성 분석은 아래의 몇가지 방식으로 분류할 수 있는데, 기술적, 경제적, 조직적 관점에서 살펴볼 수 있다.</p>
<h3 id="기술적-타당성">기술적 타당성</h3>
<p>사용자와 분석가는 비즈니스 애플리케이션 영역에 대한 이해도를 말한다. <strong>현재 보유한 기술력과 경험으로 이 프로젝트의 성공을 기대할 수 있는지를 평가</strong>하는 영역이다.</p>
<p><strong>평가 요소</strong> : 해당 기술에 대해 얼마나 경험이 있는지, 프로젝트 규모가 우리가 감당할 수 있는 수준인지, 그리고 기존의 시스템과 호환이 가능한지 등을 확인한다.</p>
<p>이를 평가할 때는 만약 이전에 사용한 프로젝트가 있으면 <strong>해당 프로젝트와 비교</strong>를 해보고, 처음이라면 <strong>IT 전문가의 조언</strong>을 받아 리스크를 분석한다.</p>
<h3 id="경제적-타당성">경제적 타당성</h3>
<p>경제적 타당성은 <strong>투입되는 전체 비용 대비 회사가 얼마나 이득을 취할 수 있는지를 확인하는 평가</strong>이다. 크게는 4가지의 과정으로 이루어진다.</p>
<p>우선 <strong>1) 비용과 이익을 계산</strong>하고, <strong>2) 가치에 대한 비용과 이익을 부여</strong>한다. (이부분이 추상적이라 어려울 수 있으나 가장 중요하고, 무형 자산의 경우에도 수치화시켜 포함해야한다.) 그리고 이를 바탕으로 <strong>3) 현금 흐름을 결정</strong>하고 결론적으로 <strong>4) 재정적 타당성을 평가</strong>한다.</p>
<p>타당성 평가에는 몇가지 지표를 이용할 수 있는데, NPV, ROI, BEP가 있다.</p>
<h4 id="npv">NPV</h4>
<p>가장 명확한 지표 중 하나이며, 단순히 <strong>유출 대비 유입의 양이 얼마나 많은지를 확인</strong>할 수 있는 지표이다. 이 때, PV(present Value)는 현금 흐름의 양을 말하고 &nbsp; $PV = (1+금리)^{n(년)}$&nbsp;으로 표현한다.</p>
<p>NPV 공식은 이러한 PV를 기반으로 $$PV 이익 - PV 비용$$&nbsp;으로 표현된다.</p>
<p>NPV가 0보다 크거나 같으면 프로젝트가 진행되어도 좋은 신호이며, 만약 0보다 작은 경우에는 적합하지 않다고 이해할 수 있다.</p>
<h4 id="roi">ROI</h4>
<p><strong>ROI(Return on Investment)는 NPV를 기반으로 계산</strong>되며, $\frac{NPV}{\sum PV(Cash ,,,outflows)}$ 으로 표현할 수 있다.</p>
<h4 id="bep">BEP</h4>
<p><strong>BEP(Break Even Point)는 손익분기점까지의 시간</strong>을 의미하고, 손익분기점을 맞기까지의 시간을 계산해 구한다. 당연하게도 이 값이 크면 프로젝트가 가지는 리스크는 정비례하게 커진다.</p>
<h4 id="tangible-cost-vs-intangible-cost">Tangible Cost vs Intangible Cost</h4>
<p>각각 유형 비용, 무형 비용을 말하며, <strong>유형 비용은 시스템을 통해 조직이 얻는 이익(수익)을 모두 포함하는 비용</strong>을 말하고, <strong>무형 비용은 숫자에 기반하기보다는 직관과 믿음에 기반을 두는 비용</strong>을 말한다.</p>
<h3 id="조직적-타당성">조직적 타당성</h3>
<p>시스템이 사용자들에게 얼마나 <strong>잘 수용되고 조직의 지속적인 운영에 얼마나 잘 통합될 것인가</strong>를 나타내는 지표이다.</p>
<p>평가 요소 : 시스템의 도입이 현재 조직에 목표와 부합하는지, 그리고 <strong>Project Champion, 관리자, 최종 사용자 등의 이해관계자(Stakeholder)를 분석</strong>한다.</p>
<p>공장의 생산 라인에 로봇 시스템이 도입되는 것을 반발하는 것과 비슷한 의미를 가지며, <strong>시스템의 도입으로 조직의 변화가 잘 이끌고 잘 수용되는지를 평가</strong>하는 것이 이 평가의 주 목적이다.</p>
<p>타당성 평가의 맹점은, 한번의 평가로 끝나는 것이 아니라 <strong>프로젝트가 이뤄지는 내내 진행되는 평가</strong>로, 지속적으로 재평가를 통해 프로젝트가 잘 순항하고 있는지를 확인해야한다.</p>
<h2 id="project-selection-issue">Project Selection Issue</h2>
<p>승인 위원회는 시스템 요구사항과 타당성 평가를 바탕으로 업무를 진행한다. <strong>비즈니스 요구사항과 시스템 구축의 위험성을 검토하여 프로젝트를 신중하게 선택</strong>한다.</p>
<h3 id="포트폴리오-관리">포트폴리오 관리</h3>
<p>동시에 포트폴리오 관리도 이어지는데, 여기서 <strong>포트폴리오란 조직이 전체적으로 가져가고자하는 프로젝트가 있는 큰 물줄기</strong>를 말한다. 전체 프로젝트의 포트폴리오에서 해당 프로젝트가 어느정도 위치에 자리하고 있는지를 확인하고, 균형 잡힌 프로젝트 포트폴리오를 구성하기 위해서는 이에 대한 절충이 필요하다. 설령 <strong>실행이 가능한 프로젝트 일지라도 포트폴리오의 문제로 인해 거부되거나 연기되는 결정이 내려질 수 있다.</strong></p>
<h1 id="project-management">Project Management</h1>
<h3 id="프로젝트-관리의-4가지-주요-절차">프로젝트 관리의 4가지 주요 절차</h3>
<p>프로젝트를 관리할 때 우리가 주요하게 거쳐야할 4가지의 절차가 있는데, <strong>1) 프로젝트의 규모를 식별</strong>하고, 팀원과 조직의 상황에 맞게 <strong>2) 업무 일정을 구성하고 관리</strong>한다. 그리고 일정에 맞게 <strong>3) 인력을 배치</strong>하고 마지막으로 <strong>4) 프로젝트의 활동을 조정</strong>한다.</p>
<p>프로젝트 관리는 서로 연관관계를 가지기에 하나를 수정하면 다른 것도 같이 수정해야한다.</p>
<h3 id="프로젝트-견적">프로젝트 견적</h3>
<p><strong>시간과 노력의 가치에 값을 매겨 예상 값어치를 산정하는 과정</strong>이다. 프로젝트에서 사용한 방법론, 경험이 있는 개발자, 실제 이전 프로젝트를 측정하며, 이를 통해서 예상 값어치를 산정한다. 처음에는 단순 범위의 수준으로 러프하게 매겨지다 <strong>프로젝트가 진행되고 구체화함에 따라 견적 또한 더욱 상세하고 두터워진다.</strong></p>
<h3 id="기능-점수function-point">기능 점수(Function Point)</h3>
<p>프로젝트가 승인되고 본격적인 계획을 들어가면 PM은 프로젝트의 규모, 비용, 개발 소요기간을 최대한 정확하게 예측해야한다. 이전에는 개발자의 경험에 의존해 되는대로 예측하기도 하였으나, 1979년 IBM의 Allen Albrecht가 Function Point라는 기능을 고안한 이후에는 이 방법을 적극 사용하여 객체적이고 정량적인 방식으로 산정한다.</p>
<p>이 기법은 5가지의 핵심 기능을 분해해 개수와 복잡도를 측정한다.</p>
<ul>
<li><strong>Input</strong> : 사용자가 시스템으로 데이터를 집어넣는 기능을 말한다.</li>
<li><strong>Output</strong> : 시스템이 데이터를 가공해 사용자에게 결과물로 보여주는 기능을 말한다.</li>
<li><strong>Query</strong> : DB의 정보를 검색과 조회를 통해 화면에 Display한다.</li>
<li><strong>File</strong> : 시스템 내부에서 자체적으로 유지, 관리하는 논리적 데이터 집합이다.</li>
<li><strong>Program Interface</strong> : 외부 다른 시스템과의 통신을 위해 필요한 게이트를 말한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/06668dd9-d6bc-4d5f-b9ff-8ef693461c71/image.png" alt=""></p>
<p>Function Point를 계산하는 데 몇 가지 절차가 존재하는데, 아래의 그림들을 중심으로 그. 흐름을 파악해 볼 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/1f224168-10b5-4581-93a7-2b995ebe9bdc/image.png" alt="">Function Point 측정</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/6097fa25-310d-4d33-8525-800867e094a2/image.png" alt="">1. Function Point 계산</th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/a6e0fdd1-a889-4590-8b5f-72b1ab39e07a/image.png" alt=""> 1-(1). Function Point 적용</th>
</tr>
</thead>
</table>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/7b3f8ae1-784d-4504-b3e0-de604a06bb04/image.png" alt=""> 2. 소요 인력 산정</th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/9a4f99c6-8027-487e-9c3f-bc76a8b76224/image.png" alt=""> 3.Schedule Time 계산</th>
</tr>
</thead>
<tbody><tr>
<td><img src="https://velog.velcdn.com/images/woong_crouch/post/c973e22a-23b5-48fb-a6cc-eec73181fa23/image.png" alt=""></td>
<td></td>
</tr>
</tbody></table>
<h2 id="use-case">Use Case</h2>
<h3 id="use-case-diagram">Use Case Diagram</h3>
<p>Use Case는 여러 시나리오를 포함하는 기능을 말하고, Actor는 외부 에이전트가 수행하는 역할이다. 인간이나 하드웨어 등의 내용이 수행하며, 이러한 Actor와 Use Case 사이의 흐름을 작성한 문서로 보면 된다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/16c40fac-55cd-4e10-9ead-afc1463c6e44/image.png" alt=""></p>
<h3 id="use-case-estimation">Use Case Estimation</h3>
<p>Use Case를 측정하는 과정을 가진다.</p>
<ul>
<li><p><strong>Unadjusted Use-Case Points(UUCP)</strong>
Actor 가중치 (1~3) / Use Case 가중치 (5,10,15)
<img src="https://velog.velcdn.com/images/woong_crouch/post/a79187e1-bb5d-4029-b826-202cc1d1b9ca/image.png" alt=""></p>
</li>
<li><p><strong>Technical Complexity Factor(TCF) : 13 factors</strong>
TCF = 0.6 + (0.01 * TFactor)
<img src="https://velog.velcdn.com/images/woong_crouch/post/7011a9a1-4a1e-4613-b7b9-8361415d04bf/image.png" alt=""></p>
</li>
<li><p><strong>Environmental Factors(EF) : 8 factors</strong>
EF = 1.4 + (-0.03 * EFactor)</p>
</li>
<li><p><strong>Adjusted Use Case Point(UCP)</strong>
UCP = UUCP * TCF * EF</p>
</li>
<li><p><strong>Effort in Person-hours = UCP * 계수(20 or 28)</strong></p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/ef538f98-6c6e-4e28-bbe7-27585d07fed1/image.png" alt=""></p>
<h1 id="creating-and-managing-the-work-plan">Creating And Managing The Work Plan</h1>
<h3 id="업무-식별">업무 식별</h3>
<p>프로젝트에 필요한 업무를 식별할 때는, 주로 방법론에서 제공하는 표준 업무 목록을 참고하거나 &quot;하향식 접근법(Top-Down)&quot;을 사용한다. 높은 레벨의 업무를 식별하고 그것을 더 작은 단위로 나눈 뒤에, 이렇게 쪼개진 업무들을 계층적으로 구조화한 것을 작업 분할 구조도(Work Breakdown Structure, WBS)라고 한다.</p>
<p>업무 식별 단계에서 업무를 누락하게 되면, 이후에 특정 팀원들에게 갑작스럽게 과중한 업무가 배정되어 불만이 쌓이고, 최악의 경우 인력 이탈이나 프로젝트의 실패로 이어질 수 있다. 고로 PM은 업무를 빠짐없이 도출하고, 공정하게 로드 밸런싱(Load Balancing) 해주는 것이 매우 중요하다.</p>
<h3 id="project-workplan">Project Workplan</h3>
<p>WBS를 바탕으로 도출된 모든 업무 목록을 모아 전체적인 작업 계획을 작성하는 것을 말하고, 아래의 내용들이 명시되어야 한다.
– 작업명
– 작업 기간
– 현재 작업 상태
– 작업 간 종속 관계
– 마일스톤 (날짜)</p>
<h3 id="tracking-project-tasks">Tracking Project Tasks</h3>
<p>작업 계획이 수립되면, PM은 일정이 계획대로 진행되는지 시각적으로 모니터링하고 관리해야한다. 이때 주로 2가지의 차트를 사용하는데, 각각 Gantt Chart, PERT Chart이다.</p>
<ul>
<li><strong>Gantt Chart</strong> : 막대 차트 형식으로, 프로젝트 진행상황을 언제든 파악하기에 용이하다.</li>
<li><strong>PERT Chart</strong> : 플로우 차트 형식으로, 주요 경로와 작업 의존도를 그리고 순서와 관계에 집중한 순서도이다,</li>
</ul>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/d06cf897-15d2-4e93-a5d0-061cdb74031f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/d06cf897-15d2-4e93-a5d0-061cdb74031f/image.png" alt=""></p>
<h2 id="refining-estimates">Refining Estimates</h2>
<h3 id="hurricane-model">Hurricane Model</h3>
<p>불확실성의 원뿔을 <strong>허리케인 모델로 시각화한 그래프</strong>로, <strong>가로축은 프로젝트의 진행 단계를 순차로 배치</strong>하고 <strong>세로축에는 소요 시간을 중심으로 구성</strong>한다. 이 때, <strong>점선은 오차범위</strong>를 의미하고 <strong>원의 크기는 해당 시점에 예상되는 프로젝트 cost</strong>를 말한다.</p>
<p>프로젝트의 진행 순서는 아래와 같이 정의하고, 각각의 레벨은 특징과 상태를 지닌다. </p>
<p><strong>Level 1 : 초기</strong>
초기에는 표준화된 프로세스가 거의 존재하지 않으며, 성공이 개발자 1~2명의 역량에 달린다. 그 사람이 나가면 프로젝트가 무너질 가능성이 급격히 높아진다.</p>
<p><strong>Level 2 : 관리</strong>
프로젝트 단위로 일정한 규칙을 마련하는 시점이고, 계획을 세우고 일정과 비용을 관리하기 시작한다. 예전과 비슷한 프로젝트를 해낼 수 있는 지점이기도 하다.</p>
<p><strong>Level 3 : 정의</strong>
회사(조직) 전체의 표준 프로세스가 확립된다. 이 시기를 기점으로 정확한 공통 가이드라인이 적용되고, 모든 팀이 메뉴얼에 따라 행동한다.</p>
<p><strong>Level 4 : 정량적 관리</strong>
데이터와 숫자로 프로세스를 관리하며, 수치를 중심으로한 대화를 주고 받는다. 이로 인해 명확한 수치를 향상시키는 것을 목표로 하기에 결과 예측의 정확도가 향상한다.</p>
<p><strong>Level 5 : 최적화</strong>
지속적인 개선과 혁신을 하는 시기로, 완성된 제품이 이미 완벽에 가까울 정도로 궤도에 올랐으나, 신기술을 도입하거나 데이터를 분석해 끊임없이 업그레이드를 하는 시기이다.</p>
<h2 id="managing-scope">Managing Scope</h2>
<h3 id="scope-creep">Scope creep</h3>
<p>Scope Creep은 프로젝트가 진행되는 도중에 새로운 요구사항이 계속해서 추가되면서, 결과적으로처음에 정했던 프로젝트의 범위(Scope)가 점점 늘어나는 현상이다. 이는 두 가지 관점을 가지는데, 일정 지연(Schedule overrun)과 예산 초과(Cose overrun)가 발생한다.</p>
<p>또한 주로 사용자가 요구사항을 늘리면 발생하게 되고, 초기예측의 불완전성을 인정하고 관리해야한다. 실제로 System Request에 비해 실제 비용은 4배(400%)까지도 차이가 발생할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/woong_crouch/post/16a8a36f-c13f-4d8b-b5dd-c348e28a7ebc/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SW Engineering & Testing (1) - Introduction]]></title>
            <link>https://velog.io/@woong_crouch/SW-Engineering-Testing-1</link>
            <guid>https://velog.io/@woong_crouch/SW-Engineering-Testing-1</guid>
            <pubDate>Wed, 18 Mar 2026 00:25:21 GMT</pubDate>
            <description><![CDATA[<h1 id="introduction">Introduction</h1>
<p>SW Engineering을 알아보기 전에, Software에 대해서 알아보자. </p>
<p>우리가 건물을 바라볼 때, 여러 관점의 사람들과 이해관계자들이 접근하게 된다. 시공자, 거주자, 설계사, 인부 등에 따라 그 건물을 바라보는 시야가 달라진다. SW도 마찬가지다. 디자이너, 개발자, 사용자, 매니저 등 여러 이해관계자의 상황에 따라 다른 관점을 가지게 된다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/8c26b0df-5f1c-487c-8298-829f1fd797d6/image.png" alt=""></p>
<p>SW란 무엇일까. 소프트웨어란 사전적 의미로 <strong>접근하면 프로그램과 프로그램의 개발, 운용, 수정 및 기능 확정을 위해 필요한 모든 정보</strong>를 말한다. 소프트웨어는 어찌보면 프로그램의 동적인 의미로 볼 수 있다. 운영체제 관점에서는 Process와도 상통하는 개념이라고 볼 수 있다.</p>
<p>이러한 SW가 가지는 특성으로는 첫째로 <em><strong>비가시성</strong>_을 가진다. 비가시성이란 무형적인 특성을 가지고 구조가 코드 속에 내제된 상태로 구현된다. 둘째로 _<strong>복잡성</strong>_을 가진다. 복잡성이란 개념을 코드로 구현한 것 자체는 복잡하고 난해한 상태를 말한다. 추가로 요구나 환경 변화에 대한 **_변경 가능성, 복제 가능성, 테스팅의 어려움 등</em>**의 특성을 가진다.</p>
<h2 id="소프트웨어-유형">소프트웨어 유형</h2>
<h3 id="소프트웨어의-분류-체계">소프트웨어의 분류 체계</h3>
<p>SW는 아래와 같은 분류 체계를 가진다.</p>
<ul>
<li><strong>기능</strong><ul>
<li>시스템 소프트웨어 : <strong>하드웨어를 직접 관리하고 원활하게 실행하는 기반을 제공</strong>한다.</li>
<li>응용 소프트웨어 : <strong>특정 목적을 위해 직접 사용하는 프로그램</strong>을 말한다.<br></li>
</ul>
</li>
<li><strong>개발 과정</strong> : reusable, newly-built, modification, porting 등이 존재한다.<br></li>
<li><strong>신뢰도</strong><ul>
<li>critical : 오류 발생 시, <strong>심각한 문제를 초래할 수 있어</strong> 신뢰성을 요하는 시스템을 말한다.</li>
<li>non-critical : 오류 발생시 불편할 수 있으나 <strong>심각한 문제가 발생하지 않는</strong> 시스템이다.<br></li>
</ul>
</li>
<li><strong>소프트웨어 크기</strong> : 규모에 따라 두 가지로 나뉜다.<ul>
<li>programming-in-the-small : <strong>규모가 작아 소수의 개발자가 단기간에 완성</strong>할 수 있는 것을 이야기하며, 개발자의 역량이 큰 영향을 준다.</li>
<li>programming-in-the-large : <strong>장기간 개발하는 대규모 프로젝트</strong>이다. 이 때는 방법론을 적절하게 적용해야한다.<br></li>
</ul>
</li>
<li>*<em>데이터 특성 *</em>: 그래픽이나 이미지, 텍스트 등의 특성을 이야기한다.</li>
</ul>
<h3 id="정보-시스템-information-system">정보 시스템 (Information System)</h3>
<p><strong>대량의 데이터의 분류, 저장, 검색에 관심을 두는 시스템</strong>으로 GUI 기반의 서비스 인터페이스를 제공한다.</p>
<p>정보 시스템의 특성을 몇 가지 알아보자면 이 시스템의 경우 문서가 중요한 요소로 작용하고, 개발이나 유지보수가 많은 노력과 비용이 발생한다. <strong>데이터 설계는 비중이 큰 반면 제어구조는 비교적 간단하다</strong>는 특징도 가지고 있다.</p>
<p>우리가 흔히 볼 수 있는 쇼핑몰 사이트나 이런 대형 사이트들이 이런 정보 시스템의 예시가 될 수 있다.</p>
<h3 id="내포-시스템-embedded-system">내포 시스템 (Embedded System)</h3>
<p>임베디드 시스템은 컴퓨터의 연산이 주 목적이 아니라 더 큰 기계나 시스템의 내부에 포함되어 제어 기능을 수행하는 소프트웨어를 말한다. 우리가 요즘에는 흔히 자동차나 냉장고 등의 전자 기기 내에 들어가는 형태로 주로 볼 수 있다.</p>
<p>특징으로는 시스템의 규모가 크고 수명이 긴 편이며, <strong>실시간 응답성</strong>이 필수적으로 접목되어야한다. 또한 오류나 장애가 발생해도 치명적인 사고를 방지할 수 있어야 한다. 마지막으로 <strong>비동기성</strong>이 특징인데 여기서 비동기성이란 작업의 완료를 기다리지 않고 바로 다음 작업을 실행하는 것을 말한다.</p>
<h2 id="소프트웨어와-관련된-사담">소프트웨어와 관련된 사담</h2>
<h4 id="질문-1-소프트웨어-시스템을-개발하는-데-드는-비용-중-프로그래밍에-드는-비용은-어느정도일까">질문 1. 소프트웨어 시스템을 개발하는 데 드는 비용 중 프로그래밍에 드는 비용은 어느정도일까?</h4>
<p>소프트웨어 시스템을 개발하는 데 드는 비용 중에 <strong>프로그래밍에 드는 비용은 20% 정도</strong>이다. 이외의 비용은 테스팅과 요구분석 및 설계가 각각 40%씩 나눠 가진다. <del>물론 모든 프로젝트가 이 추이를 따라가는 것은 아니고 전반적인 이야기이다.</del></p>
<h4 id="질문-2-사용자에게-배달되는-소프트웨어의-실행코드-1000줄-당-예상-오류의-개수는-몇-개일까">질문 2. 사용자에게 배달되는 소프트웨어의 실행코드 1000줄 당 예상 오류의 개수는 몇 개일까?</h4>
<p>보편적으로 <strong>4개 미만</strong>이라고 한다. 이는 개발 과정에서 50~60개의 오류가 발생하고 이를 보완해 사용자에게 제공되기에 현저히 떨어진 수치로 보여진다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/34f1e544-e236-4e6f-81a7-9cbdb01df1de/image.png" alt=""></p>
<h4 id="질문-3-사용자가-발견하는-시스템의-오류-중-가장-발견하기-어려운-것은-어느것일까">질문 3. 사용자가 발견하는 시스템의 오류 중 가장 발견하기 어려운 것은 어느것일까?</h4>
<p>이 질문에 대한 답은 <strong>&quot;제안서와 사용자 요구사항에 대한 잘못된 이해&quot;</strong>이다. 오류가 빠르게 발견되어 요구사항 분석 시점에 가까이 발견될수록 비용이 저렴하고 유지보수 이후로 넘어갈수록 비용이 급격하게 올라간다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/12a30382-629d-49cc-8eaf-549a261d5468/image.png" alt=""></p>
<h4 id="질문-4-소프트웨어-시스템을-유지-보수하는-데-드는-비용이-개발-비용의-몇배일까">질문 4. 소프트웨어 시스템을 유지 보수하는 데 드는 비용이 개발 비용의 몇배일까?</h4>
<p>소프트웨어 시스템을 유지 보수하는데 드는 비용은 <strong>개발 비용의 2배 가량</strong> 드는 것을 알 수 있다. 이는 제품이 얼마나 체계적으로 만들어졌는지에 따라 반비례적인 추세를 가진다. 또한 처음에 다룬 질문 1번의 내용인 비용 문제에 대한 내용과도 일부 상통하는 내용이라고 볼 수 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/dc65fe3c-7570-4897-b73f-490885f49dca/image.png" alt=""></p>
<h2 id="소프트웨어에-대한-오해">소프트웨어에 대한 오해</h2>
<p>소프트웨어에 대한 오해는 관점에 따라서 관리자, 그리고 고객과 엔지니어의 오해로 나눌 수 있다. <strong>&quot;이정도는 해줄 수 있는거 아닌가?&quot;</strong>라는 이해관계의 문제가 중심이다. 그로 인해 이해관계자들의 상황에 맞게 서로 오해의 상황이 발생한다.</p>
<h3 id="관리자의-오해">관리자의 오해</h3>
<p>관리자들은 주로 _<strong>도구, 인력, 표준화된 프로세스만 갖춰지면 프로젝트가 기계적으로 통제될 수 있다는 착각을 하는 경향</strong>_이 있다. 쉽게 말해서 자원과 틀만 제공이 되면 프로젝트가 잘 이루어질 것이라는 일종의 믿음을 가진다는 의미이다.</p>
<p>&quot;우리가 이정도 자원을 제공했으니 그들은 충분히 우리가 원하는 결과물을 만들 것이다&quot;라거나 &quot;엔지니어라면 엔지니어링에 중심을 둬야지 요구분석을 하는 것은 좋지 않다&quot;, &quot;공정이 지연되면 인력을 투입하는 방식으로 해결할 수 있다&quot; 등의 생각들이 그들이 쉽게 생각하는 오해이다.</p>
<p>자원을 제공했을 때 그에 상응하는 output이 나오기를 바라고 그러리라 믿는 경향이 있는 것이 관리자의 특징이다. 이에 따라 위와 같이 상호간의 오해가 생기기도 한다.</p>
<h3 id="고객의-오해">고객의 오해</h3>
<p>고객은 _<strong>소프트웨어의 유연성을 과대평가하여 초기에 요구사항을 명확히 하지 않아도 나중에 고칠 수 있을 것</strong>_이라 생각한다. 하지만 이 생각은 착각이고, 이후에 수정을 하는 것이 더 힘든 상황이 발생하고 설령 가능하더라도 코드가 난잡해지는 등의 문제가 발생할 가능성이 높다.</p>
<p>흔히 고객이 생각하는 방향을 예로 들자면 &quot;목표에 대한 기술만 대충 적어두면 SW를 만드는데 충분하고 세부적인건 나중에 채우면 된다&quot; 나, &quot;요구사항은 계속 변하고 이를 소프트웨어는 쉽게 수용할 수 있어야한다.&quot;는 생각을 하기 쉽다.</p>
<h3 id="엔지니어의-오해">엔지니어의 오해</h3>
<p>그럼 마지막으로 엔지니어의 오해를 알아보자. <em><strong>개발자는 코딩과 실행결과에 치중되게 생각을 하는 경향이 있다.</strong></em> 그래서 기능을 만들고 생성하는 것을 중점을 두고 유지보수를 위한 문서화나 설계에서의 품질 검증이 쉽게 넘어가곤 한다.</p>
<p>예를 들자면 &quot;프로그램이 만들어지고 작동하면 할 일을 다 한 것이다&quot; 또는 &quot;시스템을 작동시켜 보기 전까지는 품질을 평가할 방법이 없다&quot;, &quot;프로젝트의 결과는 작동하는 프로그램일 뿐이다&quot; 등의 오해를 할 수 있다.</p>
<h1 id="소프트웨어-공학">소프트웨어 공학</h1>
<h2 id="소프트웨어의-위기">소프트웨어의 위기</h2>
<p>소프트웨어를 개발할 때는 많은 문제들이 발생할 수 있다.</p>
<ul>
<li>예산 초과</li>
<li>개발 일정 지연</li>
<li>불충분한 성능</li>
<li>신뢰하기 어려운 품질</li>
<li>유지 보수의 어려움</li>
<li>막대한 유지보수 비용</li>
</ul>
<p>등이 있다. 물론 이보다 훨씬 많은 문제들이 개발이나 설계, 유지보수 과정에서 발생한다. 이 때 우리가 주의깊게 볼 위기는 <strong>하드웨어의 급속한 발전과 컴퓨터의 대중화로 SW의 수요가 급증한다</strong>는 배경을 두고 심화된다.</p>
<p>현재 대부분의 빅테크가 SW 기업인 것을 감안하면 이 사실에 대해 짐작할 수 있다. 하지만 문제는 여기서 발생한다. 소프트웨어 생산성과 생산 기술은 그에 미치지 못하는 상황이 발생한다.</p>
<h2 id="소프트웨어-공학이란-">소프트웨어 공학이란 ?</h2>
<p>소프트웨어 공학이란 <strong>품질 좋은 소프트웨어를 최소의 비용으로 계획된 일정에 맞추어 개발하기 위하여 여러가지 공학적 원리와 방법을 체계적으로 적용하는 것</strong>을 말한다. 한마디로 &quot;일정에 맞게 개발하기 위해 방법론을 적용하여 좋은 퀄리티의 소프트웨어를 제작하는 공정&quot;이다.</p>
<h2 id="소프트웨어-공학의-역사">소프트웨어 공학의 역사</h2>
<p>소프트웨어의 위기로부터 이어진 소프트웨어 공학의 역사에 대해서 알아보자. 우선 이 이야기를 하려면 1970년대부터 시작해야한다.</p>
<h3 id="1970">~1970</h3>
<p>이 시기까지 소프트웨어의 위기가 인식되기 시작하고 이를 해결하기 위해 소프트웨어 공학이 탄생한다. <strong>고급 언어가 발생하고, interactive한 프로그래밍</strong>이 생기기 시작한다. 이 때 goto 논쟁이라는 것도 발생하는데, 이는 스파게티 코드를 지양하고 논리적 흐름을 강조하는 &quot;구조적 프로그래밍&quot;이 중요하다는 것이 대두되는 기점이 된다.</p>
<h3 id="1980">~1980</h3>
<p>이제 본격적으로 소프트웨어 위기로부터의 해결책을 모색하기 시작한다. <strong>소프트웨어 공학이라는 분야가 학문적으로 정착하기 시작했고, 하드웨어로부터 독립된 개념의 소프트웨어가 점점 발생</strong>하기 시작한다. 이 때 아래와 같은 개념들이 생기기 시작했다.</p>
<ul>
<li>소프트웨어 생명주기</li>
<li>대규모 프로그래밍</li>
<li>방법론 및 도구</li>
<li>정보 은닉</li>
<li>구조적 설계</li>
</ul>
<h3 id="present">~Present</h3>
<p>80년대에 본격적으로 거론되기 시작한 해결책들은 오늘날까지 여러 방식으로 진화와 발전을 거듭해왔다. 기존의 구조적 프로그래밍의 중심을 벗어나 <strong>객체 지향 프로그래밍(방법론)이 흐름의 중심</strong>으로 다가서고, 그로인해서 재사용, 디자인 패턴, 소프트웨어 컴포넌트/설계 등의 개념들이 추가적으로 도입되기 시작한다.</p>
<h2 id="소프트웨어-공학의-크기-체계">소프트웨어 공학의 크기 체계</h2>
<p>일전에 소프트웨어 공학의 분류 체계를 하면서 나온 개념이긴 하지만 더 세세하게 개념에 대해서 알아보도록 하자.</p>
<h3 id="1-programming-in-the-small">1. Programming-in-the-Small</h3>
<p>규모가 작은 프로그램을 말하며 프로그램의 규모 자체가 작기 때문에 <strong>명확하게 정의가 가능하고 그 문제들을 집중적으로 해결하는 방식</strong>이다. 이러한 경우엔 정확하게 개발하는 것이 중요하고, 명세가 잘 변경되지 않는 특성을 가진다.</p>
<h3 id="2-programming-in-the-large">2. Programming-in-the-Large</h3>
<p>우리가 주로 마주하는 프로그램의 크기는 이 형태를 가진다. 규모가 커지게 되면서 개인의 코딩 실력이 중요한 것이 아니라 <strong>시스템 전체의 구조와 관리가 중요한 방식</strong>이다. 규모가 큰 만큼 해결할 문제를 정확하게 정의해야하고, 아무래도 크기가 크다보니 요구사항을 초기에 정한대로 흘러가지 않는 경우가 많다. 이런 경우를 고려한 상태로 대응책을 마련해야한다.</p>
<p>또한 시스템을 구성하는 컴포넌트들 사이의 인터페이스를 명확하게 설계해야하고 시스템 통합과 테스팅 과정이 필요하다. <strong>규모가 크다보니 협업이 여기서부터는 매우 중요하게 여겨지는데</strong>, 변경사항을 체계적으로 관리하는 git과 같은 툴이 적용되어야하고 지속적으로 문서, 유지보수 등을 수정하고 작업하며 탄탄히 나아가야한다.</p>
<h3 id="3-programming-in-the-many">3. Programming-in-the-Many</h3>
<p>프로그램의 크기도 크기지만 인원에 중심을 둔 프로그래밍이다. 팀 단위로 무언가를 구축할 때, 주로 마주하는 문제들을 다루고 팀원 간의 정보 교환 등의 커뮤니케이션을 진행해야한다. <strong>작업을 적당하게 할당해야하고, 표준화를 통해서 팀원들간의 문서 및 개발 성향을 조정할 필요가 있다.</strong> 결국 이 시점에 PM(Project Management)의 역량이 중요해진다.</p>
<p>사실상 Many의 경우는 Large인 프로그램에서는 필연적으로 필요한 상황이 발생하고, 규모가 크면 사람이 많아야하고 그에 따라서 2번과 3번은 유기적으로 이어질 가능성이 매우 높다.</p>
<h2 id="소프트웨어-테스팅">소프트웨어 테스팅</h2>
<h3 id="구현과-테스팅">구현과 테스팅</h3>
<p>그림 1을 통해서 <strong>프로젝트의 규모가 클수록 구현과 테스트의 비중이 줄어든다는 사실</strong>을 알 수 있고, 프로젝트에서의 구현 오류의 비중이 높은 경우를 그림2를 통해 확인할 수 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/e12b189a-c244-4d0f-ba56-e2ff2f28ea7d/image.png" alt="">
<strong>SW 코드 검증 방법과 소스코드 검증 기법</strong>은 아래와 같다.</p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/a423542b-7ace-4709-8cab-870b972bf082/image.png" alt=""><fiction>SW 코드 검증 방법</fiction></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/ae6e3e3d-2249-4084-8ca7-4082ea1ae792/image.png" alt=""><fiction>소스코드 검증 방법</fiction></th>
</tr>
</thead>
</table>
<h3 id="다양한-테스트-기법들의-오류-감지율">다양한 테스트 기법들의 오류 감지율</h3>
<p>오류 감지를 위한 여러 테스트 기법들이 존재하는데, 그 리스트를 보면 아래와 같다. 하나의 방법이 평균 75%를 넘는 경우가 없고, 그로 인해 다양한 방법을 병행으로 사용해야 효과를 볼 수 있다는 특징이 있다.
<img src="https://velog.velcdn.com/images/woong_crouch/post/a5894e16-a9bc-4239-97bf-177a6936abab/image.png" alt=""></p>
<h3 id="v-model">V-Model</h3>
<p>테스팅을 할 때, 우리는 V 모델을 자주 사용한다. <strong>V 모델은 확인 절차가 왼쪽과 오른쪽 두 개로 나뉘고, V자 모양으로 움직일 때 아래의 순차적인 절차를 따라 움직인다.</strong></p>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/e3c9ac6e-70ac-4c58-8c62-f52f716fa5d2/image.png" alt=""></th>
<th><img src="https://velog.velcdn.com/images/woong_crouch/post/e5e7493f-c8e7-41e0-990c-cccc3d433e9a/image.png" alt=""></th>
</tr>
</thead>
<tbody><tr>
<td><strong>왼쪽(Architecture Design)</strong></td>
<td></td>
</tr>
<tr>
<td>1. 요구사항 분석 : 고객이 무엇을 원하는지 요구사항을 정리한다.</td>
<td></td>
</tr>
<tr>
<td>2. 시스템 셀계: 전체 시스템의 하드웨어, 소프트웨어 구조를 기획하는 과정이다.</td>
<td></td>
</tr>
<tr>
<td>3. 아키텍처 설계 : 시스템을 구성하는 여러 모듈(기능) 간의 관계와 구조를 설계한다.</td>
<td></td>
</tr>
<tr>
<td>4. 모듈 상세 설계 : 각 모듈 내부의 구체적인 로직이나 알고리즘, 데이터 구조 등을 상세히 설계한다.</td>
<td></td>
</tr>
</tbody></table>
<p><strong>중간(Coding)</strong>
5. 코딩 : 말 그대로 프로그램을 구현하는 절차를 말한다.</p>
<p><strong>오른쪽(Testing)</strong>
6. 단위 테스트 : 개발자가 작성한 개별 함수나 클래스가 의도대로 작동하는지 테스트한다.
7. 통합 테스트 : 각각 만들어진 모듈을 연결하면 데이터가 잘 넘어가고 충돌 없이 작동하는지 테스트한다.
8. 시스템 테스트 : 완성된 전체 시스템이 정상적으로 작동하는지, 성능은 잘 나오는지 테스트한다.
9. 인수 테스트 : 최종 고객이 요구사항대로 완성되었는지 직접 사용해보며 승인하는 테스트이다.
10. 설치 테스트 : 최종 사용자의 실제 운영 환경에 소프트웨어가 문제없이 설치 및 구동되는지 테스트한다.</p>
<br>

<p>이번 포스트에서는 <strong>SW Engineering 과 Testing을 위한 개요</strong>를 알아보았다. </p>
]]></description>
        </item>
    </channel>
</rss>