17. 코드 정리하고 나누기 (모듈 시스템)/17.2 모듈의 장점

17.2.3 의존성 관리 - 필요한 재료 목록 정리하기

thejavascript4kids 2025. 7. 25. 04:17

📘 17.2.3 의존성 관리 - 필요한 재료 목록 정리하기

어머니가 요리를 시작하기 전에는 늘 같은 일을 하셨어요. 냉장고를 열어 재료들을 하나씩 꺼내어 놓으시는 거였죠. "계란찜을 만들려면 계란이 필요하고, 파도 있어야 하고..." 이렇게 중얼거리시며 필요한 것들을 차례로 준비하셨어요.

그때는 몰랐지만, 어머니는 의존성을 관리하고 계셨던 거예요. 계란찜이라는 요리가 계란과 파에 의존하고 있다는 걸 아시고, 미리 준비해두신 거죠.

오늘은 프로그래밍에서도 이처럼 어떤 코드가 어떤 다른 코드에 의존하는지 명확히 정리하는 방법인 의존성 관리에 대해 이야기해보려고 해요.

🧠 새로운 단어들과 친해지기

단어 쉬운 설명
의존성 한 코드가 다른 코드 없이는 동작할 수 없는 관계
의존성 관리 코드들 사이의 필요 관계를 체계적으로 정리하고 관리하는 방법
모듈 관계도 어떤 모듈이 어떤 모듈을 필요로 하는지 보여주는 관계도

✨ 의존성 관리가 뭐예요?

의존성 관리는 집을 지을 때의 순서와 같은 개념이에요.

우리 동네에 새 아파트가 건설되는 걸 본 적이 있나요? 건설 회사는 절대 무작정 짓지 않아요. 먼저 땅을 고르고, 기초를 다지고, 기둥을 세우고, 그 다음에 지붕을 올려요. 이 순서를 바꿀 수는 없어요. 지붕을 먼저 올릴 수는 없거든요. 지붕은 기둥이 있어야 하고, 기둥은 기초가 있어야 하니까요.

프로그래밍에서도 마찬가지예요. 어떤 코드는 다른 코드가 먼저 있어야만 작동할 수 있어요. 예를 들어:

  • 계산기 앱은 수학 함수들이 먼저 있어야 해요
  • 성적 출력 기능점수 계산 기능이 먼저 있어야 해요

🎯 왜 의존성 관리를 해야 할까요?

1. 필요한 것만 가져다 쓸 수 있어요

거대한 프로그램 전체를 가져오는 게 아니라, 정말 필요한 부분만 골라서 사용할 수 있어요.

2. 코드 구조를 쉽게 파악할 수 있어요

"이 기능을 사용하려면 저 기능이 먼저 필요해!"라는 관계를 명확히 알 수 있어요.

3. 문제 해결이 빨라져요

어떤 부분에 오류가 생겼을 때, 그 부분과 관련된 다른 부분들을 쉽게 찾을 수 있어요.

4. 함께 일하기가 좋아져요

여러 사람이 함께 큰 프로젝트를 할 때, 각자 맡은 부분의 의존성만 알면 되니까 효율적으로 작업할 수 있어요.

⚙️ 의존성 관리 기본 사용법

의존성 관리의 기본은 importexport를 사용하는 거예요. 이를 통해 "나는 이것이 필요해!"라고 명확히 표현할 수 있어요.

// math-tools.js - 수학 도구들 (기초가 되는 모듈)
export function add(a, b) {
  return a + b;    // 더하기 기능
}

export function multiply(a, b) {
  return a * b;    // 곱하기 기능  
}

// calculator.js - 계산기 (math-tools에 의존)
import { add, multiply } from './math-tools.js';

export function calculate(a, b, operation) {
  if (operation === 'add') {
    return add(a, b);        // math-tools의 add 사용
  } else if (operation === 'multiply') {
    return multiply(a, b);   // math-tools의 multiply 사용
  }
}

// app.js - 메인 앱 (calculator에 의존)
import { calculate } from './calculator.js';

const result = calculate(5, 3, 'add');
console.log(result);   // 8

이렇게 하면 app.jscalculator.jsmath-tools.js 순서로 의존성이 연결되어 있다는 것을 명확히 알 수 있어요.

🧪 실제 예제로 연습하기

🔹 예제 1: 학교 성적 관리 시스템의 의존성 구조

// config.js - 설정 정보 (가장 기본이 되는 모듈)
export const schoolName = "행복초등학교";
export const subjects = ["국어", "수학", "과학", "사회"];
export const gradeStandards = {
  A: 90,
  B: 80, 
  C: 70,
  D: 60
};

// calculator.js - 점수 계산 기능 (config에 의존)
import { gradeStandards } from './config.js';

export function calculateAverage(scores) {
  if (scores.length === 0) return 0;

  let total = 0;
  for (let i = 0; i < scores.length; i++) {
    total += scores[i];
  }
  return Math.round(total / scores.length);
}

export function getGrade(score) {
  if (score >= gradeStandards.A) return "A";
  if (score >= gradeStandards.B) return "B";
  if (score >= gradeStandards.C) return "C";
  if (score >= gradeStandards.D) return "D";
  return "F";
}

// report.js - 성적표 출력 (config와 calculator에 의존)
import { schoolName, subjects } from './config.js';
import { calculateAverage, getGrade } from './calculator.js';

export function createReport(studentName, scores) {
  let report = `\n📋 ${schoolName} 성적표\n`;
  report += `👤 학생명: ${studentName}\n`;
  report += `━━━━━━━━━━━━━━━━━━━━\n`;

  // 과목별 점수와 등급 표시
  for (let i = 0; i < subjects.length; i++) {
    const subject = subjects[i];
    const score = scores[i];
    const grade = getGrade(score);
    report += `${subject}: ${score}점 (${grade})\n`;
  }

  // 평균 점수와 등급 표시
  const average = calculateAverage(scores);
  const averageGrade = getGrade(average);
  report += `━━━━━━━━━━━━━━━━━━━━\n`;
  report += `📊 평균: ${average}점 (${averageGrade})\n`;

  return report;
}

// main.js - 메인 프로그램 (모든 모듈에 의존)
import { createReport } from './report.js';

const students = [
  { name: "김철수", scores: [85, 92, 78, 88] },
  { name: "이영희", scores: [95, 87, 91, 94] }
];

console.log("🎓 성적 관리 시스템");

for (let i = 0; i < students.length; i++) {
  const student = students[i];
  console.log(createReport(student.name, student.scores));
}

이 예제에서 의존성 관계를 살펴보면:

  • main.jsreport.js에 의존해요
  • report.jsconfig.jscalculator.js에 의존해요
  • calculator.jsconfig.js에 의존해요
  • config.js는 다른 모듈에 의존하지 않는 기초 모듈이에요

🚨 자주 하는 실수들

❌ 실수 1: 순환 의존성 만들기

// 잘못된 방법
// a.js
import { funcB } from './b.js';
export function funcA() { return funcB() + 1; }

// b.js  
import { funcA } from './a.js';  // ❌ 순환 의존!
export function funcB() { return funcA() + 2; }

올바른 방법: 공통 기능을 별도 모듈로 분리하세요.

❌ 실수 2: 너무 많은 의존성

// 잘못된 방법
import * as moduleA from './a.js';
import * as moduleB from './b.js';
import * as moduleC from './c.js';
// ... 수십 개의 모듈

// 올바른 방법: 정말 필요한 것만 가져오기
import { neededFunction } from './helper.js';

✏️ 연습 문제를 시작하기 전에

이제 여러분이 직접 의존성을 관리해볼 시간이에요. 마치 어머니가 요리 전에 재료를 하나씩 확인하시듯이, 코드에서도 어떤 기능이 어떤 다른 기능을 필요로 하는지 차근차근 정리해보는 거예요.

처음에는 복잡해 보일 수도 있어요. 하지만 이렇게 정리해두면 나중에 코드를 고치거나 새로운 기능을 추가할 때 훨씬 쉬워져요. 차분하게 따라해보세요.

문제 1: 간단한 쇼핑몰 시스템의 의존성 구조 만들기

// products.js - 상품 정보 (기초 모듈)
export const products = [
  { id: 1, name: "연필", price: 500 },
  { id: 2, name: "지우개", price: 300 },
  { id: 3, name: "노트", price: 1000 }
];

export function getProductById(id) {
  return products.find(product => product.id === id);
}

// cart.js - 장바구니 기능 (products에 의존)
import { getProductById } from './products.js';

export let cart = [];

export function addToCart(productId, quantity) {
  const product = getProductById(productId);
  if (!product) {
    return "상품을 찾을 수 없습니다.";
  }

  cart.push({ product, quantity });
  return `${product.name} ${quantity}개를 장바구니에 추가했습니다.`;
}

export function getCartTotal() {
  let total = 0;
  for (let i = 0; i < cart.length; i++) {
    total += cart[i].product.price * cart[i].quantity;
  }
  return total;
}

// checkout.js - 결제 기능 (cart에 의존)
import { cart, getCartTotal } from './cart.js';

export function processPayment() {
  if (cart.length === 0) {
    return "장바구니가 비어있습니다.";
  }

  const total = getCartTotal();
  cart.length = 0;  // 장바구니 비우기
  return `결제 완료! 총 ${total}원이 결제되었습니다.`;
}

문제 2: 사용해보기

// shop.js - 쇼핑몰 메인 (모든 모듈에 의존)
import { addToCart, getCartTotal } from './cart.js';
import { processPayment } from './checkout.js';

console.log("🛒 쇼핑몰 시작!");

// 장바구니에 상품 추가
console.log(addToCart(1, 2));  // "연필 2개를 장바구니에 추가했습니다."
console.log(addToCart(3, 1));  // "노트 1개를 장바구니에 추가했습니다."

// 총액 확인
console.log(`총액: ${getCartTotal()}원`);  // "총액: 1500원"

// 결제 처리
console.log(processPayment());  // "결제 완료! 총 1500원이 결제되었습니다."

🎯 16단원 복습 - 생성자 함수와 의존성

16단원에서 배운 생성자 함수도 의존성 관리를 할 수 있어요.

// user.js - 사용자 생성자 함수
function User(name, age) {
  this.name = name;
  this.age = age;
}

User.prototype.introduce = function() {
  return `안녕하세요! 저는 ${this.name}이고 ${this.age}살입니다.`;
};

export default User;

// admin.js - 관리자 생성자 함수 (User에 의존)
import User from './user.js';

function Admin(name, age, permission) {
  User.call(this, name, age);  // User 생성자 호출
  this.permission = permission;
}

Admin.prototype = Object.create(User.prototype);
Admin.prototype.constructor = Admin;

Admin.prototype.manage = function() {
  return `${this.name}이(가) ${this.permission} 권한으로 관리합니다.`;
};

export default Admin;

// app.js - 사용하기
import User from './user.js';
import Admin from './admin.js';

const user = new User("민수", 12);
const admin = new Admin("선생님", 30, "전체");

console.log(user.introduce());   // "안녕하세요! 저는 민수이고 12살입니다."
console.log(admin.introduce());  // "안녕하세요! 저는 선생님이고 30살입니다."
console.log(admin.manage());     // "선생님이(가) 전체 권한으로 관리합니다."

📝 정리하기

오늘은 의존성 관리에 대해 배웠어요:

  1. 의존성은 한 코드가 다른 코드 없이는 동작할 수 없는 관계예요
  2. import와 export로 의존성을 명확히 표현해요
  3. 필요한 것만 가져다 쓰고, 구조 파악이 쉬워지고, 문제 해결이 빨라져요
  4. 순환 의존성을 피하고 정말 필요한 것만 의존해야 해요
  5. 16단원의 생성자 함수도 의존성 관리를 할 수 있어요

의존성 관리를 잘 하면 더 체계적이고 관리하기 쉬운 코드를 만들 수 있어요!

✅ 학습 완료 체크리스트

학습 내용 이해했나요?
의존성의 기본 개념
import/export로 의존성 표현
순환 의존성 문제 회피
실전 예제 따라하기
16단원 내용과의 연결

📂 마무리 정보

오늘 배운 17.2.3 내용이 여러분의 자바스크립트 지식 상자에 잘 저장되었나요? 다음 시간에는 더 재미있는 내용으로 만나요!

기억할 점: 의존성 관리는 어머니가 요리 전에 재료를 정리하는 것과 같아요. 미리 정리해두면 나중에 훨씬 수월하답니다!



🚀 더 체계적인 JavaScript 학습을 원하신다면?
이 포스팅에서 다룬 내용을 실제로 실습해보세요!
무료 JavaScript 학습 플랫폼에서 단계별 학습과 실시간 코드 실행을 통해
더욱 효과적이고 재미있게 학습하실 수 있습니다.
📝 실시간 코드 실행 📊 학습 진도 관리 👥 체계적 커리큘럼
📚 171개 체계적 학습레슨 · 📋 855개 4지선다 연습문제 · 🆓 완전 무료 · ⚡ 즉시 시작