설계[Software Engeerning]

SnowCat·2023년 2월 2일
0

CS - Software Engeerning

목록 보기
5/9
post-thumbnail

설계란?

  • 사용자의 요구사항에 따라 요구분석명세서를 만들면 이를 기반으로 어떻게 소프트 웨어를 구축할 것인지를 결정하는 것
  • 요구분석과의 차이는 아래 표와 같음
구분요구분석설계
산출물요구분석명세서설계서
관점whathow
특성개념적, 추상적사용 환경을 반영해 구체적
비교플랫폼(운영체제, 프레임워크 등)을 고려하지 않음비기능 요구사항, 제약사항, 플랫폼 고려

설계의 원리

1. 분할과 정복

  • 개발에 있어서 규모가 큰 문제를 작은 규모의 모듈로 분할하는 것
  • 웹 페이지를 만들 때 여러 component로 세분화 한 다음 가장 바닥의 컴포넌트부터 만들어 가는 과정을 생각하면 됨
  • 너무 모듈을 자잘하게 분할하면 모듈사이 통신횟수가 증가해 복잡도가 증가할 수 있음

2. 추상화

  • 자신에게 필요한 특징만 표현하는 것
  • 복잡한 세부 사항들에 대한 고려 없이 로직 사용에 집중할 수 있게 해주는 것
    객체지향에서 공통점을 찾아내는 추상화와는 다름

2-1. 과정 추상화

  • 프로그래밍 전에 상세한 내용을 생략하고 전체 흐름만 알고리즘 형태로 작성하는 것
  • 가령 등수별로 학점을 자동으로 입력하는 알고리즘을 만든다 하면, 과목, 정렬 방법 등에 대한 내용을 생략하고 다음과 같이 적음
    학생 데이터 파일 읽기 -> 학생 한명의 점수를 계산함 -> 비율에 맞게 학점을 잘라줌 -> 학생 이름, 점수, 학점 출력
  • 아래와 같이 함수를 분리하는 과정도 추상화라고 볼 수 있음
const printSumResult = () => {
  const result = GetSum(10);
  console.log(`1-10의 합: ${result}`)
}

const getSum(num: number) => {
  let sum = 0;
  for(let i = 1; i <= num; i++) {
    sum += i;
  }
  return sum;
}

2-2. 데이터 추상화

  • 데이터와 데이터 구조를 감추어 사용자는 기능 사용에 집중할 수 있도록 해주는 것
  • 클래스를 통해 정보를 캡슐화 하는 것이 데이터 추상화의 대표적인 예시임

2-3. 제어 추상화

  • 프로그래밍 언어에서 쓰는 제어 구조를 추상화하는 것
  • 제어 추상화 단계가 올라갈수록 표현이 간결해지고 특징만 나타내게 됨

어셈블리어

section .data
  msg db "Hello World"

section .text
  global_start

_start:
	mov rax, 1
	mov rdi, 1
	mov rsi, msg
	mov rdx, 12
	syscall
	mov rax, 60
	mov rdi, 0
	syscall

c언어

#include <stdio.h>

int main() {
	printf("Hello World!");
}

python

print('Hello, world!')

3. 캡슐화

  • 사용자로 하여금 데이터에 직접 접근을 금지하고, 객체의 메서드만을 통해 접근하도록 하는 방식
  • 사용자는 객체의 사용방법만 알면 되고, 객체 제공자는 모듈 내부의 자료구조, 알고리즘 등의 변경의 부담이 줄어들게 됨
  • 또한 캡슐화를 통해 객체 사이의 독립성이 구조적으로 보장됨
    데이터 추상화가 내부 구현과 기능을 분리하는 것이라면, 캡슐화는 외부의 직접적인 정보 조작을 차단하는 것
    아래의 스택 예시에서는 private data를 메서드만으로 접근하게 하는것이 캡슐화, 스택에 필요한 자료구조, 알고리즘을 숨기는 것이 데이터 추상화

typescript

class Stack<T> {
  private size: number;
  private data: T[] = [];
  constructor(num: number) {
    this.size = num >= 1 ? Math.floor(num) : 1
  }
  getMaxSize () {
    return this.size;
  }
  getCurrentSize () {
    return this.data.length;
  }
  push (item:T) {
    if (this.data.length < this.size) {
        this.data.push(item);
    } else {
        throw console.log("full stack");
    }
  }
  pop() {
    if (this.data.length !== 0) {
        return this.data.pop();
    } else {
        throw console.log("empty stack");
    }
  }
}

4. 정보은닉

  • 캡슐화 자체만으로 내부 정보가 외부에 숨겨지지는 않음
  • 추가로 private 설정을 해야 같은 시스템 내부의 다른 요소에서 객체에 직접 접근하는 것을 차단할 수 있음

5. 상속

  • 상위 클래스의 내용의 모든 것을 하위 클래스가 물려받아 사용하는 것을 의미함
class NameStack<T> extends Stack<T>{
    private name: string;
    constructor(num: number, name: string) {
        super(num);
        this.name = name;
    }
    getName () {
        return this.name;
    }
}

6. 다형성

오버로딩

  • 중복 정의라고도 부르며 비슷한 타입이나 기호를 중복정의할 때, 동일한 함수명을 사용하지만 입력받는 인자가 다를 때 사용 가능
  • 이 때 구별할 수 있는 매개변수의 개수나 자료형 같은 요소를 시그니쳐라 부름
interface Coordinate {
    x: number;
    y: number;
}

function parseCoordinate(obj: Coordinate): Coordinate;
function parseCoordinate(x: number, y: number): Coordinate;
function parseCoordinate(arg1: unknown, arg2?: unknown): Coordinate {
    let coord: Coordinate = {
        x: 0,
        y: 0,
    }
    if (typeof arg1 === 'object') {
        coord = {
            ...(arg1 as Coordinate)
        }
    } else {
        coord = {
            x: arg1 as number,
            y: arg2 as number,
        }
    }

    return coord;
}

오버라이딩

  • 부모 클래스에서 정의된 변수, 메서드 등을 무시하고 새로 정의해서 사용하는 것
  • 이 때 상위 클래스의 객체는 언제나 자신의 하위 클래스 객체로 교환 가능해야 한다는 리스코프 교체 원칙이 준수되어야 함
/* 리스코프 교체 원칙 미준수
abstract class Instructor {
    constructor() {}
    getMoney(time:number) {
        return 120000 * time;
    }
  }
*/

// 리스코프 교체 원칙 준수
abstract class Instructor {
     getMoney(price:number, time:number): number {
        return price * time;
     };
  }

class InstructorOne extends Instructor {
    getMoney(time:number) {
    return 90000 * time;
  }
}

모듈화

  • 모듈이란 규모가 큰 코드를 여러개로 나눈 조각이며 소프트웨어 구조를 이루는 기본 단위이기도 함
  • 모듈은 다음과 같은 특징을 가짐
    • 다른것과 구별되는 독립적인 기능을 갖는 단위(unit)임
    • 유일한 이름을 가짐
    • 다른 프로그램이나 모듈에서 모듈을 호출할 수 있음
    • 모듈화를 통해 코드의 가독성을 높이고, 유지보수의 난이도를 낮출 수 있음
  • 모듈화를 할 때는 모듈 간의 결합은 느슨하게, 모듈 내 구성 요소 간의 응집은 강하게 해야 함
  • 모듈간에도 상호 의존관계를 가지며, 호출 관계, 데이터 전달 관계, 제어 관계로 분류할 수 있음
  • 모듈을 평가하기 위해서는 응집도와 결합도를 고려해야 함

응집도

  • 응집도는 하나의 모듈 안에서 구성 요소 간에 긴밀히 뭉쳐 있는가를 의미함
  • 모듈 하나가 단일 기능으로 구성되면 응집도가 가장 높고, 우연히 모듈로 묶인 경우는 응집도가 가장 낮음

    기능적 응집: 단일 기능의 요소가 하나의 모듈 구성
    순차적 응집: 한 모듈의 결과를 다른 모듈의 입력으로 사용하는 두 요소를 결합한 모듈
    교환적 응집:같은 입력을 사용하는 요소가 하나의 모듈이 되거나 구성 요소가 동일한 출력을 만들어내는 모듈이 되는 것
    절차적 응집: 몇개의 순서를 이루는 구성 요소가 하나로 묶인 경우
    시간적 응집: 리액트의 생명주기 요소처럼 구성 요소들이 같은 시간에 실행된다는 이유로 묶인 경우
    논리적 응집: 모듈 간에 공통점이 있는 것을 하나로 묶은 경우
    우연적 응집: 아무런 이유 없이 우연히 모여 구성된 모듈

결합도

  • 모듈과 모듈 사이의 관계를 가지는 정도
  • 모듈간의 상호 연관성이 최대한 없게, 있더라도 제어보다는 매개변슈를 사용한 데이터만의 교환을 하는 것이 바람직함

    데이터 결합: 매개변수를 통해 데이터만 주고받음으로써 간섭을 최소화하는 결합
    스탬프 결합: C언어의 구조체처럼 데이터 이외에 배열이나 자료구조같은 추가적인 데이터를 주고받는 결합
    제어 결합: 제어 플래그를 매게변수로 사용하며 서로 간섭이 가능한 모듈 관계
    공통 결합: global 변수를 공통으로 사용하는 결합
    내용 결합: 모듈 간에 인터페이스를 사용하지 않고 직접 이동하는 방법, C언어에서 goto를 사용하는 것과 비슷

사용자 인터페이스 설계

  • 사용하기 편리한 소프트웨어를 설계하기 위해서는 사용자 인터페이스를 불편하지 않고 예상대로 움직이도록 설계해야함
  • 사용자 인터페이스를 설계할 떄는 다음과 같은 지침을 충분히 고려해야함
    • 사용법을 배우기 쉬워야 함
    • 사용하기 편리해야 함
    • 사용자가 데이터 입력을 제어할 수 있어야 함
    • 사용자의 입력에 반응해야 함
    • 도움말을 제공해야 함
    • 일관성을 유지해야 함
    • 입력 작업은 최소로 해야 함
    • 효율성을 고려해야 함
    • 사용자 오류에 대한 되돌리기 기능을 제공해야 함
    • 삭제 또는 취소 버튼 클릭 시 재확인을 요구해야 함
    • 사용하기 쉽게 직관적이여야 함

출처:
쉽게 배우는 소프트웨어 공학 2판, 김치수, 한빛아카데미

profile
냐아아아아아아아아앙

0개의 댓글