Share
Sign In
Lighthouse Dev
TDD(Test-Driven Development)
L
Lighthouse
👍
안녕하세요, 오늘은 TDD(Test-Driven Development)에 대해 이야기하려 합니다.
TDD
소프트웨어 개발 방법론 중 하나로, 개발 과정에서 테스트를 우선하여 작성하고 이를 통과시키는 것에 초점을 두는 방법론입니다.
코드를 작성하기 이전에 테스트 케이스를 작성하고, 이를 통과하기 위한 그에 맞는 기능을 작성하는 작업을 반복하여 개발합니다.
TDD의 장점과 한계
TDD의 장점:
1.
품질 향상: 개발자는 코드의 동작을 확실히 이해하고 테스트 케이스를 통해 코드의 정확성을 검증할 수 있어, 더 견고하고 안정적인 코드를 작성할 수 있습니다.
2.
리팩토링 지원: 코드를 작은 단위로 분리하고 테스트 가능한 형태로 작성하여 코드의 구조와 설계를 개선하기 쉽게 합니다.
3.
빠른 피드백: 작은 단위의 테스트를 빠르게 실행하고 결과를 확인하여 버그를 빠르게 발견하고 수정할 수 있으며, 코드 변경에 대한 피드백을 신속하게 받을 수 있습니다.
4.
협업 강화: 테스트 코드가 개발 프로세스의 일부로 문서화되어 있어 다른 개발자들과의 협업을 용이하게 하며, 코드의 동작을 이해하고 검증하는 데 도움이 됩니다.
TDD의 한계:
1.
시간과 노력: 테스트 코드를 작성하기 위해 추가적인 시간과 노력이 필요하며, 개발 시간이 늘어날 수 있습니다.
2.
설계에 대한 이해: 테스트 케이스를 작성하기 위해 개발자는 코드의 설계에 대한 깊은 이해가 필요하며, 이를 갖추지 않으면 테스트 케이스가 미흡해질 수 있습니다.
3.
복잡한 시나리오의 테스트: 복잡한 시나리오나 UI, 성능 테스트 등은 TDD로 테스트하기 어려울 수 있습니다.
4.
변동이 많은 요구사항: 요구사항이 자주 변경되는 경우, 테스트 케이스를 계속 수정해야 하는 상황이 발생할 수 있습니다.
이러한 장점과 한계로 인해 TDD는 초기에는 추가 비용이 들 수 있지만, 시간이 지남에 따라 비용을 절감할 수 있는 특징을 지녔습니다.
TDD의 사이클
Lifecycle of the Test-Driven Development method
출처:
https://ko.wikipedia.org/wiki/테스트_주도_개발
1.
Write Test: 기능을 검증할 테스트 케이스를 작성
2.
Test Fails: 작성한 테스트 케이스를 실행하여 실패하는 것을 확인
3.
Write Code: 테스트를 통과할 수 있는 코드를 작성
4.
Test Passes: 작성한 코드가 테스트를 통과하는지 확인
5.
Refactor: 코드를 개선하고 리팩토링하는 단계
예시코드
유효한 이메일을 검증하는 기능의 개발을 가정하고 프로세스를 진행해보겠습니다.
1.
Write Test : 테스트 코드 작성
import pytest # 유효한 이메일 테스트 def test_valid_email(): email = "test@example.com" assert validate_email(email) == True # 유효하지 않은 이메일 테스트 def test_invalid_email(): email = "invalid_email" assert validate_email(email) == False
2.
Test Fails : 실패하는 테스트 실행
3.
위 테스트 코드에서는 **validate_email** 함수가 구현되지 않았으므로 모든 테스트는 실패
4.
Write Code: 코드 작성
5.
주어진 이메일이 유효한지 여부를 확인하는 validate_email 함수를 작성
import re def validate_email(email): # 이메일 형식을 정규표현식을 사용하여 검증 pattern = r'^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$' if re.match(pattern, email): return True else: return False
6.
Test Passes: 테스트 통과
============================= test session starts ============================== collecting ... collected 2 items test_file.py::test_valid_email PASSED [ 50%] test_file.py::test_invalid_email PASSED [100%] ============================== 2 passed in 0.01s ===============================
7.
Refactor: 리펙토링
import re def validate_email(email): # 이메일 형식을 정규표현식을 사용하여 검증 pattern = r'^[\w\.-]+@[a-zA-Z\d\.-]+\.[a-zA-Z]{2,}$' return bool(re.match(pattern, email)) # 유효한 이메일 테스트 def test_valid_email(): email = "test@example.com" assert validate_email(email) == True # 유효하지 않은 이메일 테스트 def test_invalid_email(): email = "invalid_email" assert validate_email(email) == False
TDD를 실제 적용하기 위한 난관들
실제 적용 사례에서 얘기하는 문제들
팀 내 새로운 개발 방법의 도입의 어려움
일정문제
생산성 문제
테스트 코드 작성의 어려움
미숙한 TDD 도입
미숙한 TDD의 도입은 아래 그림과 같이 개발 초기에 들인 노력에 비해 효과를 얻을 수 없었습니다.
효과
TDD를 도입한 기업들은 코드의 품질 향상과 버그의 조기 발견, 개발자 간의 협업 강화 등의 이점을 봤습니다.
또한 요구사항 변경에 유연하게 대응할 수 있는 더 민첩한 개발 프로세스를 구축할 수 있었습니다.
결론
위와 같은 어려움으로 인해서 그런지 모르겠지만 찾아본 실제 적용한 사례들은 주로 테스트 범위를 한정시켜 TDD를 적용시켰습니다.
또한, 카카오뱅크 TDD 사례에서는 기존 코드를 바탕으로 테스트 코드를 새로 작성하며, TDD 접근 방식으로 테스트 코드를 작성하는게 얼마나 어려운지 보여주었습니다.
공부를 하며 TDD는 결과물의 높은 코드 품질을 유지하는 데 매력적이지만, 도입을 실제 적용하기에는 많은 문제들을 헤쳐나가야한다는 점을 느낄 수 있었습니다.
그래서 다음 시간에는 테스트 코드를 작성하는 법에 대해서 한번 공부해보려고합니다.
참고자료
이론
실제 TDD 적용 사례
Kp
Subscribe to 'kpmg-lighthouse'
Welcome to 'kpmg-lighthouse'!
By subscribing to my site, you'll be the first to receive notifications and emails about the latest updates, including new posts.
Join SlashPage and subscribe to 'kpmg-lighthouse'!
Subscribe
👍
donggyun_woo
SQLAlchemy 알아보기
시작 하면서 최근 KRM ver2.0 프로젝트를 시작하면서 웹서버를 구현하기 위해 SQLAlchemy를 사용하면서 모델링을 했습니다. 작업을 하면서 SQLAlchemy에 대해 공부한 내용을 공유해 보겠습니다. SQLAlchemy? SQLAlchemy는 파이썬을 위한 SQL 툴킷 및 Object-Relational Mapping(ORM) 라이브러리로, 데이터베이스와의 상호작용을 보다 쉽고 직관적으로 할 수 있게 도와줍니다. SQLAlchemy는 데이터베이스 연결 관리, 트랜잭션 관리, 스키마 정의 및 관리 등 다양한 기능을 제공합니다. SQLAlchemy 구조 크게 Core와 ORM으로 나뉘어져 있습니다. Core (SQL Expression Language): SQLAlchemy의 Core는 SQL 표현 언어를 사용하여 데이터베이스 쿼리를 생성하고 실행하는 데 중점을 둡니다. SQLAlchemy Core는 SQL을 직접 작성하고 데이터베이스와 상호작용할 수 있는 저수준 인터페이스를 제공합니다. Engine 데이터베이스와의 연결을 관리하는 핵심 구성 요소입니다. Engine 객체는 데이터베이스와의 상호작용을 위한 연결 풀(Connection Pool) 및 데이터베이스 드라이버를 포함하여 SQLAlchemy의 다른 부분과의 통신을 조정 Engine의 주요 기능 데이터베이스 연결 설정: Engine은 데이터베이스 URL을 통해 데이터베이스 연결 정보를 설정합니다. 연결 풀 관리: Engine은 연결 풀을 관리하여 데이터베이스 연결의 효율성을 높이고 성능을 최적화합니다. 연결 풀은 데이터베이스 연결을 재사용하여 연결 생성 및 소멸에 따른 오버헤드를 줄입니다. 트랜잭션 관리:
👍🏻
1
Lighthouse_JSH
Airflow 트러블슈팅 공유
안녕하세요! 오늘은 제가 Airflow를 사용하면서 겪었던 몇 가지 트러블슈팅 경험을 공유하고자 합니다. 제 경험이 여러분의 Airflow 작업에 도움이 되기를 바랍니다. 디렉토리 구조 제가 구성한 Airflow의 디렉토리 구조는 다음과 같습니다. 추가한 디렉토리에서 import 시 에러 발생 새로운 디렉토리인 config와 db에서 import하려고 시도했을 때 import 오류가 발생했습니다. 이는 프로젝트 경로를 path에 추가하여 해결했습니다. path를 추가하며 운영 환경과 개발 환경의 경로가 다르기 때문에 다른 문제가 발생했는데 이는 아래에서 다시 설명드리겠습니다. plugins와 dags/utils 처음에는 azure_conn과 slack_message 두 개의 스크립트를 plugins 디렉토리에 저장했습니다. 하지만 GCP Composer 서비스에서는 dags 폴더 하위에 폴더를 생성하도록 권장하기 때문에 코드 재사용성을 위해 두 스크립트를 dags/utils 디렉토리로 이동했습니다. plugins 디렉토리는 Airflow 시스템의 기본 기능 확장에 사용합니다. 출처: https://cloud.google.com/composer/docs/how-to/using/installing-python-dependencies?hl=ko#use_packages_that_depend_on_shared_object_libraries API 호출 에러 사례 스케줄러나 웹 UI를 통해 DAG를 실행할 때 Negsignal.SIGSEGV 오류가 발생하여 requests 호출이 중단되었습니다. 로컬에서 테스트 실행해 보니 문제 없이 동작했지만, 이 오류는 이미 GitHub 디스커션에 등록되어 있었습니다. 출처: https://github.com/apache/airflow/discussions/24463#discussioncomment-4404542 원인은 명확하게 밝혀지지 않았지만, macOS에서는 프록시 정보를 가져오는 시스템 호출이 특정 조건 하에서 예상치 못한 방식으로 작동하여 메모리 접근 오류인 SIGSEGV(세그먼테이션 폴트)를 발생시키는 것으로 추측됩니다. 해결방법은 dag에 아래의 코드를 추가해 프록시 설정을 초기화하였습니다. 실행 환경 차이로 인한 코드 불일치 위 에러들로 인해 실행 환경과 개발환경 간 코드가 불일치했습니다. 이를 해결하고자 config/airflow_config/config.json을 두어 실행 환경을 읽어 환경에 따라 같은 코드로 다르게 동작하도록 수정했습니다. Connections 등록 후 PW를 까먹은 경우
김원준
파이썬의 동시성 관리 : GIL 과 멀티 스레딩
0. 들어가며 저번 시간에는 동시성. 즉, 제어권에 대한 Blocking/NonBolocking. 또 작업의 순서를 논하는 Sync/Async에 대해 간단하게 살펴보았다. 그렇다면 이번 시간에는 다음 순서로 파이썬의 GIL 및 스레드 환경에 대해 살펴보자. 0-1. 들어가기 앞서 ! 오늘 발표를 조금 더 잘 이해할 수 있도록 하기 위해, 몇가지 용어에 대한 설명을 준비하였다. 메모리란 ? 메모리는 컴퓨터가 프로그램과 데이터를 저장하고 처리하는 데 사용되는 저장 공간이다. 프로그램의 실행 중에 생성되는 데이터는 물리적인 메모리에 저장 되며(주로 RAM), 이 데이터는 스레드가 실행되면서 읽고 쓰게 된다. 프로세스란 ? 실행 중에 있는 프로그램을 의미한다. 작업(Task)과 같은 의미로 쓰인다. 프로세스는 최소 하나의 스레드를 가지는데, 실제로 작업(Task)이 스레드 단위로 동작한다. 스레드란 ? 스레드는 프로그램 내에서 실행되는 흐름의 단위. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램의 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이것이 바로 멀티스레딩이다. 프로세스 구조 프로세스의 데이터와 명령어가 있는 영역은 Code(Text), Data, Stack, Heap이다. 💡각 프로세스는 별도의 공간(독립된 메모리)에서 실행되고 프로세스끼리는 자원의 공유를 하지 않는다. 그렇다보니, 프로세스 간의 자원을 공유하기 위해서는 별도의 통신이 필요하다. 스레드 구조 스레드는 Stack만 따로 할당받고, Code(Text), Data, Heap 영역은 프로세스의 자원을 공유한다. 💡자원을 공유하다보니, 시스템의 자원과 처리 비용이 멀티 프로세싱에 비해 적다. (통신의 부담X) 하지만 자원을 공유하고 있다 보니, 멀티 스레딩 환경에서 동기화의 문제가 발생할 수 있다.
❤️
2