2025. 5. 20. 21:22ㆍDart & Flutter
📖 목차
1. 협업을 위한 필수 도구 Git
2. 리눅스 환경의 디렉토리, 파일 경로
3. 해시 알고리즘
4. Flutter에서 파일 입출력 라이브러리
5. TDD
6. Dart 언어의 test 라이브러리를 통해 테스트 작성하는 방법
📌 1. 협업 도구 Git 기본 개념
Git이란?
Git은 버전 관리 도구입니다.
코드를 수정하거나 기능을 추가하다 보면 이전 상태로 되돌리고 싶을 때가 있습니다.
또한 여러 사람이 함께 개발할 때는 누가, 어떤 코드를, 왜 수정했는지를 명확하게 관리할 필요가 있죠.
Git은 이러한 문제를 해결해주는 분산 버전 관리 시스템(DVCS)입니다.
Git의 핵심 개념
저장소(Repository): Git이 코드를 추적하고 관리하는 공간
로컬 저장소(Local Repo): 내 컴퓨터에 있는 Git 저장소
원격 저장소(Remote Repo): GitHub, GitLab 같은 서버에 있는 저장소
커밋(Commit): 코드 변경 내용을 저장하는 스냅샷
브랜치(Branch): 독립적으로 개발을 진행할 수 있는 작업 공간
병합(Merge): 브랜치를 하나로 합치는 작업
Git 설치 및 설정
1. Git 설치
• 공식 다운로드 링크
Git - Downloads
Downloads macOS Windows Linux/Unix Older releases are available and the Git source repository is on GitHub. Latest source Release 2.49.0 Release Notes (2025-03-14) Download Source Code GUI Clients Git comes with built-in GUI tools (git-gui, gitk), but ther
git-scm.com
2. 사용자 정보 설정
git config --global user.name "조성은"
git config --global user.email "you@example.com"
이 정보는 커밋할 때 ‘누가 수정했는지’ 기록되므로 꼭 설정해 주세요!
Git 기본 사용 흐름
# 1. 저장소 초기화
git init
# 2. 파일을 스테이징
git add main.dart
# 3. 커밋 (스냅샷 저장)
git commit -m "처음으로 main.dart 파일 추가"
# 4. 원격 저장소 연결 (GitHub와 연동할 때)
git remote add origin https://github.com/username/repo.git
# 5. 원격 저장소로 업로드
git push -u origin main
브랜치 (Branch)란?
브랜치는 기능 개발이나 실험을 기존 코드에 영향 없이 진행할 수 있게 해주는 도구입니다.
# 브랜치 생성
git branch feature/login
# 브랜치 전환
git checkout feature/login
# 또는 한 줄로
git checkout -b feature/login
예시 시나리오
• main 브랜치는 배포 가능한 안정된 코드
• feature/login 브랜치는 로그인 기능을 개발하는 브랜치
• 기능 개발 완료 후 main 브랜치로 merge!
변경 이력 보기
git status # 현재 변경사항 확인
git log # 커밋 히스토리 보기
git diff # 변경된 코드 내용 확인
실습 예제
1. Git으로 첫 저장소 만들기
mkdir my_project
cd my_project
git init
touch main.dart
git add main.dart
git commit -m "첫 커밋"
2. GitHub에 연동하기
• GitHub에서 새 저장소 생성 → URL 복사
git remote add origin https://github.com/yourname/my_project.git
git push -u origin main
협업할 때 Git을 사용하는 방법
브랜치 전략
• main: 배포용
• develop: 개발 중인 코드
• feature/: 기능 단위 브랜치 (예: feature/calendar-ui)
• hotfix/: 긴급 수정 브랜치
협업 시 꿀팁
• 자주 pull해서 팀원 코드 반영
• 커밋 메시지는 명확하고 간결하게
feat: 로그인 기능 추가
fix: 회원가입 오류 수정
refactor: 불필요한 코드 정리
정리
• Git은 코드의 타임머신입니다. 잘 활용하면 언제든 과거로 돌아갈 수 있어요!
• 초보일수록 작은 단위로 자주 커밋하는 습관을 들이세요.
• GitHub, GitLab 같은 플랫폼을 활용하면 협업도, 이력 관리도 편리해집니다.
📌 2. Linux 환경에서 디렉토리와 파일, 경로
Linux는 왜 중요한가?
개발자라면 터미널과 친해져야 해요.
iOS, Android, 웹, 서버 등 어떤 분야의 개발자든,
Linux나 Unix 기반의 환경에서 터미널 명령어를 사용하는 상황은 반드시 생깁니다.
Flutter나 Dart로 개발할 때도, CLI 명령어를 입력하는 경우가 많죠.
이 글에서는 디렉토리/파일 관리 명령어와 경로 개념을 쉽고 빠르게 정리해볼게요.
디렉토리와 파일 관리 기본 명령어
1. 디렉토리 관련 명령어
ls: 현재 디렉토리 안의 파일/폴더 목록 보기
pwd: 현재 작업 중인 디렉토리 경로 출력
cd: 디렉토리명 디렉토리 이동
mkdir: 폴더명 새 디렉토리 만들기
rmdir: 폴더명 비어있는 디렉토리 삭제
2. 파일 관련 명령어
touch: 파일명 새 파일 생성
rm: 파일명 파일 삭제
cp: 원본 복사본 파일 복사
mv: 원본 새이름 파일 이름 변경 / 이동
cat: 파일명 파일 내용 출력
예제 실습
mkdir my_folder
cd my_folder
touch hello.txt
ls # hello.txt 확인
cat hello.txt
경로(Path)란 무엇인가?
경로는 파일 또는 폴더의 ‘위치’입니다.
Linux는 트리 구조로 모든 파일과 폴더를 관리합니다.
경로에는 두 가지 종류가 있습니다:
| 경로 종류 | 설명 | 예시 |
| 절대 경로 | 루트 /부터 시작하는 전체 경로 | /home/username/project/main.dart |
| 상대 경로 |
현재 위치 기준의 경로 | ../main.dart, ./lib/utils.dart |
- 특수 기호
| 기호 | 의미 |
| . | 현재 디렉토리 |
| 현재 | 디렉토리 |
| ~ | 사용자 홈 디렉토리 (/home/사용자명) |
실전 예시
cd ~/Desktop/my_project # 내 바탕화면 프로젝트 폴더로 이동
cd .. # 한 단계 위로 이동
ls ./lib # lib 폴더 안의 파일 목록 보기
실습 예제: 간단한 디렉토리 구조 만들기
mkdir flutter_app
cd flutter_app
mkdir lib assets
touch main.dart lib/home.dart assets/logo.png
ls -R
-R 옵션은 재귀적으로 폴더 안까지 모두 보여줍니다.
CLI 명령어 단축키 & 팁
↑ / ↓: 이전 명령어 불러오기
Tab: 자동완성 (파일/디렉토리 이름)
Ctrl + L: 터미널 화면 지우기 (clear와 동일)
Ctrl + C: 실행 중인 명령 중지
정리
• Linux 환경은 파일과 디렉토리 중심으로 움직입니다.
• GUI 환경과 달리, CLI에서는 경로를 정확히 이해해야 원하는 파일을 다룰 수 있어요.
• 개발자는 터미널을 능숙하게 다룰수록 빠르고 강력하게 작업할 수 있습니다.
📌 3. 해시 알고리즘(Hash Algorithm)
해시(Hash)란?
해시는 아무 길이의 데이터를 고정된 길이의 문자열로 바꿔주는 기술입니다.
이렇게 변환된 결과를 해시값(hash value) 또는 다이제스트(digest)라고 부릅니다.
예시
입력: "hello"
출력: 5d41402abc4b2a76b9719d911017c592 (MD5 해시)
한 글자만 바꿔도 결과가 완전히 달라져요!
해시 알고리즘의 특징
고정 길이 출력: 입력 길이에 관계없이 항상 일정한 길이의 해시값을 생성
결정적(Deterministic): 같은 입력이면 항상 같은 출력
빠른 계산 속도: 빠르게 변환 가능
충돌 회피: 서로 다른 입력이 같은 해시값을 갖기 어렵도록 설계됨
비가역성(역으로 복원 불가능): 해시값만 보고 원래 데이터를 알 수 없음
해시 알고리즘의 주요 용도
1. 무결성 검사 (Integrity Check)
파일이 변경되었는지 확인할 때 사용
→ 파일을 열지 않고도 “이게 원본과 같은지” 확인 가능!
2. 비밀번호 저장
비밀번호를 그대로 저장하지 않고 해시값으로 저장
→ 해커가 DB를 털어도 원래 비밀번호는 모름!
3. 디지털 서명 & 인증
전자서명, 인증서 등에서도 해시를 사용하여 문서 위조 여부 확인
4. Git의 버전 관리
Git은 커밋 내용을 해시값으로 식별함 → 정확하고 빠르게 변경 이력을 추적 가능
Git에서 해시 알고리즘은 어떻게 쓰일까?
Git은 내부적으로 SHA-1 해시 알고리즘을 사용하여 커밋, 트리, 블롭 등 모든 객체에 고유한 ID(해시값)를 부여합니다.
$ git log
commit 9a1f35b7a8c342718f994dcf849e88be89e7c6e7
Author: 조성은 <you@example.com>
Date: Mon May 20 14:00:00 2025 +0900
🎉 초기 커밋: 프로젝트 구조 세팅
위의 긴 문자열이 바로 SHA-1 해시값!
이 값은 커밋한 파일, 작성자, 시간, 메시지 등 모든 정보의 조합을 바탕으로 생성되며,
1바이트라도 달라지면 전혀 다른 해시값이 생성됩니다.
즉, Git은 해시값을 기반으로 변경 이력을 추적하고, 무결성을 보장합니다.
SHA-1 외에 다른 해시 알고리즘
| 알고리즘 | 해시 길이 | 보안성 | 설명 |
| MD5 | 128비트 | 낮음 | 빠르지만 충돌이 쉽게 발생 |
| SHA-1 | 160비트 | 낮음 (Git 기본값) | Git에서 주로 사용하지만 보안 취약점 있음 |
| SHA-256 | 256비트 | 높음 | 보안성이 높아 최근 대체로 사용 |
| SHA-3 | 256/512비트 등 | 매우 높음 | 새로운 구조로 설계된 안전한 해시 |
해시 충돌(Collision)이란?
서로 다른 입력인데 같은 해시값이 나오는 현상을 충돌(Collision)이라고 합니다.
해시 충돌이 발생하면:
• 무결성 보장에 문제가 생길 수 있음
• 보안적으로 치명적일 수 있음 (예: 위조된 문서를 원본처럼 보이게 할 수 있음)
그래서 보안 분야에서는 SHA-256 이상을 권장하는 추세예요.
직접 해시값 구해보기 (CLI 실습)
- Linux/macOS에서
echo -n "hello" | sha1sum
# 결과: aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
echo -n "hello!" | sha1sum
# 결과: 561f9a0786684aeb7a962ca7ee40c8a6d490d6c5
느낌표 하나만 달라도 전혀 다른 해시값이 생성되는 걸 확인할 수 있습니다.
정리
• 해시 알고리즘은 데이터를 고정된 길이의 문자열로 바꾸는 변환 함수입니다.
• Git은 커밋의 고유 ID로 SHA-1 해시값을 사용해 변경 이력을 추적합니다.
• 보안과 무결성 보장을 위해 해시 알고리즘은 필수적인 기술입니다.
📌 4. Flutter의 파일 입출력 라이브러리
– dart:io 라이브러리로 데이터 저장하고 불러오기
파일 입출력이란?
입력(Input): 파일에서 내용을 읽어오기
출력(Output): 파일에 내용을 저장하기
예를 들어 앱에서 유저가 쓴 글을 저장하거나, 로컬 설정 값을 기록하고 불러오는 기능이 필요할 때 파일 입출력(File I/O)이 사용돼요.
Flutter에서 사용하는 주요 라이브러리
Flutter에서는 Dart 기본 라이브러리인 dart:io를 통해 파일을 다룰 수 있어요.
단, 파일 시스템은 웹 환경에서는 지원되지 않고, 모바일, 데스크탑 등 로컬 파일 시스템이 존재하는 플랫폼에서만 동작해요.
- import 방법
import 'dart:io';
import 'package:path_provider/path_provider.dart';
1) 저장할 위치 얻기 – path_provider
Flutter에서 앱 전용 저장 경로를 얻으려면 path_provider 패키지를 사용해야 해요.
pubspec.yaml에 추가
dependencies:
path_provider: ^2.1.2
경로 불러오기 예시
Future<String> getLocalPath() async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
2) 파일에 문자열 저장하기
- 예제 코드: 텍스트 저장
Future<File> writeToFile(String content) async {
final path = await getLocalPath();
final file = File('$path/data.txt');
// writeAsString은 문자열을 파일에 씀
return file.writeAsString(content);
}
3) 파일에서 문자열 읽어오기
- 예제 코드: 텍스트 읽기
Future<String> readFromFile() async {
try {
final path = await getLocalPath();
final file = File('$path/data.txt');
// 파일 내용 읽어오기
return await file.readAsString();
} catch (e) {
return '파일을 읽을 수 없습니다: $e';
}
}
전체 흐름 실습
void main() async {
await writeToFile('Flutter는 짱이야!');
final content = await readFromFile();
print('파일 내용: $content');
}
출력 결과:
파일 내용: Flutter는 짱이야!
유용한 파일 관련 메서드들
exists() : 파일이 존재하는지 확인
delete() : 파일 삭제
create() : 파일 생성
readAsString() : 문자열로 읽기
writeAsString('내용') : 문자열로 쓰기
주의사항: 비동기 처리
dart:io는 대부분의 함수가 Future 기반으로 동작하므로 await, async를 꼭 사용해야 해요!
추가: 여러 줄 쓰기 & 리스트 저장하기
Future<void> writeList(List<String> lines) async {
final path = await getLocalPath();
final file = File('$path/log.txt');
final sink = file.openWrite(); // Stream 방식으로 쓰기 시작
for (final line in lines) {
sink.writeln(line);
}
await sink.close(); // 꼭 닫아줘야 저장됨!
}
정리
• Flutter에서 파일 입출력은 dart:io와 path_provider를 조합해서 사용해요.
• 파일 경로는 getApplicationDocumentsDirectory()를 통해 확보해요.
• 파일은 비동기적으로 읽고/쓸 수 있으며, 앱 데이터 저장에 활용할 수 있어요.
📌 5. TDD와 Dart 테스트 라이브러리로 단위 테스트 완전 정복!
– 테스트 주도 개발로 Flutter 앱의 품질을 높이자
TDD란?
“테스트 코드를 먼저 작성하고, 그 테스트를 통과하는 코드를 구현하는 개발 방식”이에요.
3단계 순환 구조
1. 실패하는 테스트 작성 (Red)
2. 테스트를 통과시키는 최소한의 코드 작성 (Green)
3. 코드 리팩토링 (Refactor)
Red → Green → Refactor → (반복!)
이 과정을 반복하면서 점점 신뢰할 수 있는 코드를 만들어나가는 게 바로 TDD!
왜 TDD를 써야 할까?
버그 예방: 사전에 테스트를 짜서 버그 발생률 ↓
유지보수 용이: 코드 수정 시 테스트가 보호막 역할
문서화 효과: 테스트 코드 자체가 “어떻게 동작해야 하는지” 보여줌
심리적 안정감: 뭔가 고쳐도 기존 기능이 잘 돌아가는지 즉시 확인 가능
Dart에서 테스트하려면?
Flutter 또는 Dart 프로젝트에서 test 라이브러리를 사용하면 단위 테스트를 손쉽게 작성할 수 있어요!
1) test 라이브러리 설치
✅ pubspec.yaml에 추가
dev_dependencies:
test: ^1.24.0
dev_dependencies에 추가해야 해! 테스트는 개발할 때만 사용하니까 😎
2) 테스트 파일 구조 만들기
예시 구조
/lib
calculator.dart
/test
calculator_test.dart ← 여기에 테스트 코드 작성!
3) 예제 – 간단한 계산기 테스트
- 먼저 로직부터 구현: lib/calculator.dart
class Calculator {
int add(int a, int b) => a + b;
int subtract(int a, int b) => a - b;
}
- 테스트 코드 작성: test/calculator_test.dart
import 'package:test/test.dart';
import '../lib/calculator.dart';
void main() {
group('Calculator 테스트', () {
test('덧셈 테스트', () {
final calc = Calculator();
expect(calc.add(3, 2), 5);
});
test('뺄셈 테스트', () {
final calc = Calculator();
expect(calc.subtract(5, 2), 3);
});
});
}
4) 테스트 실행하기
- 터미널에서 실행
dart test
- 성공 시 출력
00:00 +2: All tests passed!
두 개의 테스트가 모두 통과했습니다.
테스트 작성 시 자주 쓰는 함수들
test() : 개별 테스트를 정의
group() : 여러 테스트를 묶어서 그룹화
expect(actual, matcher) : 예상 결과 비교
setUp() : 각 테스트 전에 실행되는 코드
tearDown() : 각 테스트 후 정리 코드
테스트를 반복 작성하는 팁
• 기능 하나 만들면 → 바로 테스트도 하나 추가!
• 에러가 나면 → 테스트 먼저 만들고 수정!
• 테스트 실패는 “망했다”가 아니라 “이제 고치면 된다!”는 신호 🔔
정리
• TDD는 테스트 → 구현 → 리팩터링의 반복을 통해 안정적인 코드를 만드는 개발 방식이에요.
• Dart의 test 라이브러리를 사용하면, 간단하게 단위 테스트를 작성할 수 있어요.
• Flutter 개발에서도 상태관리, 유틸 함수, 모델 로직 등 비 UI 영역에서 적극 활용돼요.
'Dart & Flutter' 카테고리의 다른 글
| [Flutter] 병렬 처리와 스레드 이해 (Thread, Isolate, 레이스 컨디션) (0) | 2025.05.28 |
|---|---|
| [Flutter] 비동기 프로그래밍 핵심 개념 정리 (Observer, Pub/Sub, Event Loop) (1) | 2025.05.27 |
| [Flutter] 함수형 프로그래밍(Functional Programming) (1) | 2025.05.14 |
| [Flutter] 객체지향 프로그래밍(OOP) (0) | 2025.05.14 |
| [Dart & Flutter] 개발자를 위한 프로세스 메모리 구조 이해 (0) | 2025.05.07 |