응집도와 결합도

응집도와 결합도는 소프트웨어 모듈화 설계에서 코드의 품질을 평가하는 핵심 개념입니다. 두 개념은 모듈 간의 관계와 모듈 내부의 일관성을 정의하며, 시스템의 유지보수성, 확장성, 재사용성에 영향을 미칩니다.

응집도

응집도Cohesion는 모듈 내부의 요소들이 얼마나 밀접하게 관련되어 있는지를 나타냅니다. 응집도가 높을수록 모듈이 하나의 명확한 목적을 달성하며, 기능적으로 일관된 작업을 수행합니다. 높은 응집도는 모듈화 설계에서 중요한 목표로, 모듈이 특정 기능이나 책임에 집중하게 만들고, 코드의 가독성과 유지보수성을 향상 시킵니다.

응집도의 종류

우연적 응집도

우연적 응집도Coincidental Cohesion는 기능적으로 관련 없는 작업들이 하나의 메서드나 클래스에 모여 있는 경우 발생하는 가장 낮은 수준의 응집도입니다.

public class Utility
{
    public void PerformTasks()
    {
        LogActivity("Task started");
        AddBookToLibrary("Book1");
        SendEmailToUser("admin@example.com", "Task started");
    }
}

위 클래스는 로그 기록, 책 추가, 이메일 전송과 같이 관련 없는 작업들이 한 메서드에 모여 있어 우연적 응집도를 나타냅니다.

논리적 응집도

논리적 응집도Logical Cohesion는 논리적으로 비슷한 작업을 처리하지만, 실제로는 서로 다른 기능이 한 클래스에 모여 있는 경우 발생합니다.

public class LibraryManager
{
    public void ManageLibrary(int operationCode, string book)
    {
        if (operationCode == 1) AddBook(book);
        else if (operationCode == 2) RemoveBook(book);
        else if (operationCode == 3) UpdateBook(book);
    }
    private void AddBook(string book) { /*...*/ }
    private void RemoveBook(string book) { /*...*/ }
    private void UpdateBook(string book) { /*...*/ }
}

위 클래스는 논리적으로 책을 관리하는 여러 작업들을 한 곳에 모았지만, 각각의 기능은 서로 독립적입니다.

시간적 응집도

시간적 응집도Temporal Cohesion는 같은 시점에 수행되는 여러 작업들이 한 모듈에 묶여 있는 경우 발생합니다.

public class LibraryInitialization
{
    public void InitializeLibrary()
    {
        LoadBooksFromDatabase();
        SetupUserAccounts();
        InitializeLoggingSystem();
    }
}

위 클래스는 라이브러리 시스템이 시작될 때 필요한 여러 작업을 모아두었습니다. 이러한 작업들은 시간적 응집도를 가집니다.

절차적 응집도

절차적 응집도Procedural Cohesion는 특정 절차나 흐름에 따라 연관된 작업들이 모여 있는 경우 발생합니다.

public class BookBorrowing
{
    public void BorrowBook(string userId, string bookId)
    {
        CheckBookAvailability(bookId);
        ReserveBookForUser(userId, bookId);
        SendBorrowingNotification(userId, bookId);
    }
}

위 클래스는 책을 대출하는 절차에 따라 여러 작업을 묶었으며, 절차적 응집도를 보여줍니다.

통신적 응집도

통신적 응집도Communicational Cohesion는 동일한 데이터 구조나 입력을 처리하는 작업들이 모여 있는 경우 발생합니다.

public class BookReportGenerator
{
    public void GenerateBookReport(BookData bookData)
    {
        CalculateBookStatistics(bookData);
        GenerateBookSummary(bookData);
        PrintBookReport(bookData);
    }
}

위 클래스는 같은 BookData를 사용하여 보고서를 생성하는 여러 작업이 통신적 응집도를 나타냅니다.

기능적 응집도

기능적 응집도Functional Cohesion는 모듈 내 모든 작업이 하나의 기능을 중심으로 수행되는 경우 발생합니다.

public class UserAuthentication
{
    public bool AuthenticateUser(string username, string password)
    {
        var user = GetUserByUsername(username);
        return VerifyUserPassword(user, password);
    }
}

위 클래스는 사용자 인증이라는 단일 기능을 수행하며, 기능적 응집도가 높습니다.

결합도

결합도Coupling는 모듈 간의 의존성을 나타냅니다. 결합도가 낮을수록 모듈 간의 의존성이 적고, 모듈이 독립적으로 변경될 수 있으며, 시스템의 확장성, 유지보수성이 높아집니다. 결합도가 높으면 모듈 간에 강한 의존성이 존재하여, 하나의 모듈이 변경될 때 다른 모듈도 함께 수정되어야 하는 문제가 발생할 수 있습니다.

결합도의 종류

내용 결합

내용결합Content Coupling은 한 모듈이 다른 모듈의 내부 데이터를 직접 참조하는 경우 발생하는 가장 높은 수준의 결합도입니다.

public class Book
{
    public string ISBN { get; set; }
}
public class BookManager
{
    public void ManipulateBookData(Book book)
    {
        book.ISBN = "978-123456789";  // Book 클래스의 내부 데이터에 직접 접근
    }
}

BookManagerBook 클래스의 내부 데이터에 직접 접근하는 것은 내용 결합의 예로, 매우 높은 결합도를 나타냅니다.

공유 결합

공유 결합Common Coupling은 전역 변수를 여러 모듈에서 공유하는 경우 발생합니다.

public static class GlobalLibrarySettings
{
    public static string LibraryName;
}
public class LibraryManager
{
    public void SetLibraryName(string name)
    {
        GlobalLibrarySettings.LibraryName = name;
    }
}
public class UserInterface
{
    public void DisplayLibraryName()
    {
        Console.WriteLine(GlobalLibrarySettings.LibraryName);
    }
}

LibraryManagerUserInterface가 전역 상태를 공유하므로 공유 결합이 발생합니다.

외부 결합

외부 결합External Coupling은 모듈들이 외부의 데이터 형식이나 파일 형식에 의존하는 경우 발생합니다.

public class CsvBookLoader
{
    public void LoadBooksFromCsv(string filePath)
    {
        // CSV 파일 형식에 의존
    }
}
public class LibraryManager
{
    private CsvBookLoader _csvLoader;
    public LibraryManager(CsvBookLoader csvLoader)
    {
        _csvLoader = csvLoader;
    }
    public void LoadBooks()
    {
        _csvLoader.LoadBooksFromCsv("books.csv");
    }
}

여기서는 CsvBookLoader와 LibraryManager가 외부 파일 형식인 CSV에 의존하므로 외부 결합이 발생합니다.

제어 결합

제어 결합Control Coupling은 한 모듈이 다른 모듈의 흐름을 제어하는 경우 발생합니다.

public class Logger
{
    public void Log(string message, bool detailed)
    {
        if (detailed)
            Console.WriteLine("Detailed Log: " + message);
        else
            Console.WriteLine("Log: " + message);
    }
}
public class LibraryManager
{
    private Logger _logger;
    public LibraryManager(Logger logger)
    {
        _logger = logger;
    }
    public void ProcessLibraryData(bool detailedLog)
    {
        _logger.Log("Library data processed", detailedLog);  // 제어 결합
    }
}

LibraryManagerLogger의 동작 방식을 제어하기 때문에 제어 결합이 발생합니다.

스탬프 결합

스탬프 결합Stamp Coupling은 모듈 간에 복잡한 데이터 구조를 전달할 때 발생하는 결합입니다.

public class BookDetails
{
    public string Title { get; set; }
    public string Author { get; set; }
    public string ISBN { get; set; }
}
public class BookCatalog
{
    public void AddBook(BookDetails details)
    {
        // BookDetails 객체에 의존
    }
}

BookCatalogBookDetails의 전체 구조를 전달받기 때문에 스탬프 결합이 발생합니다.

자료 결합

자료 결합Data Coupling은 모듈 간에 필요한 데이터만 주고받는 경우로, 결합도가 가장 낮습니다.

public class BookCatalog
{
    public void AddBook(string title, string author)
    {
        // 필요한 정보만 전달받음
    }
}

이 방식은 필요한 데이터만 전달받기 때문에 결합도가 낮습니다.

맺음말

응집도와 결합도는 소프트웨어 설계에서 모듈화의 품질을 평가하는 중요한 기준입니다. 높은 응집도와 낮은 결합도를 유지함으로써 시스템의 유지보수성과 확장성을 극대화할 수 있으며, 코드의 가독성과 재사용성도 향상됩니다. 이러한 원칙을 도서관리 시스템과 같은 프로젝트에 적용하면 더욱 효율적이고 유연한 소프트웨어를 개발할 수 있습니다.