[Service] 소프트웨어 엔지니어링
소프트웨어 엔지니어링
- 소프트웨어 엔지니어링이란?
-
소프트웨어를 개발하는 과정에서 체계적이고 효율적인 방법을 사용하여 소프트웨어의 품질과 유지보수성을 보장하는 학문 분야

-
- 소프트웨어는 다양한 분야가 있고, 집중하는 문제가 다르다.
- 프론트엔드 : 웹페이지의 앞단
- 백엔드(서버) : 데이터 처리, 연산, API 등을 진행
- 풀스택 : 프론트엔드 + 백엔드 등 여러가지 진행
- 머신러닝, AI
- 데이터
- 모바일 앱 : 앱 개발
- 게임, 보안
- DevOps, 클라우드 : 클라우드 리소스 효율적인 사용
- 소프트웨어 엔지니어들은 여러 규칙과 방법론을 사용해서 개발한다.
소프트웨어 개발 라이프사이클
- Planning(계획) $\rightarrow$ Analysis(요구조건분석) $\rightarrow$ Design(설계) $\rightarrow$ Implementation(구현) $\rightarrow$ Testing & Integration(테스트) $\rightarrow$ Mainenance(유지 보수)
- 위 단계를 계속해서 반복한다.
소프트웨어 설계
-
아래는 좋은 소프트웨어 설계를 위해서 알아야 하는 개념이다.
- 모듈성
- 모듈이란 고유한 목적, 기능을 가지는 단위다.
- 레고 블록과 유사하다. 블록마다 고유한 용도가 존재하며, 쉽게 부착하거나 제거할 수 있다. 또한 나머지 부분에 영향을 주지 않으면서 쉽게 교체가 가능하다.
-
소프트웨어 개발의 모듈성은 큰 프로그램을 작고 독립적인 부분으로 나누는 것을 의미한다.

- 예를 들어 계산기를 구현한다면, “입력 모듈 + 연산 모듈 + 출력 모듈 + 메모리 모듈 + 인터페이스 모듈” 로 나눠볼 수 있다.
- 응집도(Cohesion)
-
시스템의 모듈 구성 요소가 목적을 달성하기 위해 관련되어 있는 정도

- 아래의 Class 는 하나의 모듈이 여러가지 일(기능)을 담당한다. 공동의 목적이 없고, 관련되어 있지 않다.
-
즉 낮은 응집도를 가진다. 이처럼 낮은 응집도를 가지는 코드는 하나의 클래스에 모든 것이 정의된다.

- 반면에 아래의 Class 가 높은 응집도를 가지는 코드다. 각각의 모듈이 긴밀하게 엮이고, 각각의 모듈이 하나의 역할을 담당한다.
User: 유저의 정보를 만들고 저장하는 역할UserInformation: 유저 정보를 출력하는 역할EmailSender: 이메일을 유저에게 전송하는 역할- 이처럼 Class 를 나눠서 각각의 역할을 부여하는 것이 높은 응집도를 가질 수 있다.

- 높은 응집도의 코드를 짜려면 Class, 객체 지향적 사고가 필요하다. 하나의 Class 에 모든 기능을 구현하는 것이 아닌, 목적에 맞게 나누고 서로 교류하는 인터페이스를 구현하는 것이다.
-
- 결합도(Coupling)
-
모듈 간 상호 의존성의 정도를 나타낸다.

-
하나의 클래스에서 수정했을 때 다른 클래스도 수정을 해야 한다면, 높은 결합도를 가지는 코드다. 아래 그림에서 오른쪽이 낮은 결합도를 가지는 코드다.

Order에서Product의 메서드를 사용하지 않게 되면,Product의self.price관련 구현 정보와 상관없이 실행이 가능하다. 결합도가 높으면 원하는 결과가 다른 클래스의 수정에 따라 다른 결과로 발생할 수 있다.- 즉 다른 클래스 내부의 구현이 바뀌어도 영향을 받지 않는 것이 낮은 결합도이다.
-
- 좋은 소프트웨어 설계 지향점
- 높은 응집도(모듈 내 교류)와 느슨한 결합도(모듈 끼리는 덜 교류)를 가진 소프트웨어를 지향해야 한다.
- 소프트웨어 설계 혹은 Pytorch 클래스를 만들 때, 응집도와 결합도를 체크해보자.
- 이 블로그에서 설계 용어 측면에서의 응집도와 결합도를 잘 설명하고 있다.
- 모듈성
테스트
- 유저에게 우리가 제공하는 기능을 제공하기 전에 사전 테스트를 진행해야 한다.
- 소프트웨어 개발의 테스트는 프로그램이 예상대로 작동하고 문제가 없는지 확인하는 과정이다. 유저에게 공개하기 전에 프로그램이 잘 작동하는지 확인하는 과정이 없으면 장애를 경험하기 쉽다.
-
테스트를 통해 기대되는 결과(현상)와 실제 나온 결과를 비교한다. 즉 사용자들에게 안정적으로 소프트웨어를 사용할 수 있도록 기능이 추가될 때 기존 시스템에서 오류가 생기는지 버그가 있는지 등을 확인한다.

- 개발 과정에서 모두 테스트를 할 수 있다. 코드만 확인하는 것이 아닌 전체 시스템에 대한 확인도 할 수 있다.
- 요구 조건 확인, 아키텍처 디자인 설계 확인, 서버 정상 확인, 데이터베이스 연결 확인, 서버 부하 테스트 등이 가능하다.
테스트의 종류
- Unit Test : 개별 단위 테스트를 말한다. 함수를 테스트 할 때도 Unit test 라고 볼 수 있다. pytest 라는 라이브러리로 가능하다.
- Integration Test : 다른 단위, 구성요소의 동작을 테스트한다. 즉 여러가지 함수를 같이 사용하는 경우에 해당한다.
- End to End Test : 처음부터 끝까지 모두 테스트한다. 서버가 올라가는지, API 요청이 되는지, 어떻게 동작하는지 등을 확인한다.
- Performance Test : 성능, 부하 테스트
- 딥러닝 프레임워크에서의 테스트는 잘 발전되지 않은 부분이 있다. 딥러닝에서는 데이터와 코드로 같이 테스트를 해야 하기 때문이다.
- 그러나 소프트웨어 설계에서는 코드 단위 테스트를 쉽게 할 수 있다.
문서화
- 소프트웨어를 이용하기 위한 README, API 문서, 아키텍쳐 문서 등을 작성하는 것이 좋다. Pytorch 깃허브의
README.md가 매우 올바른 예시다. - Pytorch 공식문서에는 API 설명서, 사용 가이드, Ecosystem(관련된 다른 라이브러리), Blog, Tutorial 등이 모두 있다. 즉 좋은 소프트웨어는 좋은 문서가 같이 존재한다.
- 따라서 개인 프로젝트도 문서화를 신경쓰면 좋다.
소프트웨어 엔지니어링을 배워야 하는 이유
-
아래는 Hidden Technical Debt in Machine Learning Systems 논문의 그림이다. 여기서 알 수 있는 것은, 코드(검은 부분)는 매우 작은 일부에 불과하다는 것이다.

-
예시로 트위터의 아키텍쳐를 보자.

- Prediction Service(home score 예측) 와 Candidate Source(Feature 를 뽑아 Scoring) 가 AI 와 관련된 아키텍처다.
- 모델보다 크고 복잡한 시스템에서 제 역할을 하기 위해 소프트웨어 엔지니어링을 이해해야 한다.
- 큰 아키텍처 안에 AI 가 들어가 있다는 것을 알고 있는 것이 핵심이다. 유튜브 추천 알고리즘 또한 큰 아키텍처 안에 들어가 있다.
- AI 모델을 개발하고 서비스에 녹이기 위한 과정을 위해 소프트웨어 엔지니어링(소프트웨어 개발, 프론트엔드 & 백엔드)을 학습하는 것이 필요하다.
- 프로덕트 프로토타이핑, 변환 품질, 인퍼런스 속도에 대해서도 생각해보자.
- 정리하면, 서비스에 ML/AI 기술들을 적용하기 위해서는 서비스와 그를 만들어 내는 소프트웨어 엔지니어링을 이해해야 한다.
댓글 남기기