⭐ 동기 (Synchronous)
동기란 데이터의 요청과 결과가 동시에 이루어지는 것을 의미합니다.
예를 들어, 사용자가 서버에 데이터를 요청하면, 그 요청에 대한 응답이 있을 때까지 사용자는 다른 작업을 수행할 수 없습니다.
✅ 특징
- 즉각적인 응답 요구: 사용자가 요청을 보낸 후, 즉각적으로 응답이 돌아오기를 기대합니다.
- 사용자 경험: 대기 시간이 길어지면 사용자 경험이 저하될 수 있습니다. 사용자는 응답을 기다리는 동안 아무것도 할 수 없기 때문에, 이 과정에서 피로감이 느껴질 수 있습니다.
동기 방식은 일반적으로 간단한 요청-응답 패턴에 적합하며, 작은 데이터 전송이나 상태가 중요한 작업에서 유용합니다.
⭐ 비동기 (Asynchronous)
비동기는 요청과 응답이 동시에 이루어지지 않는 것을 의미합니다.
사용자가 서버에 요청을 보낸 후, 그 응답을 기다리지 않고 다른 작업을 수행할 수 있습니다.
이 방식은 사용자가 대기하지 않고도 여러 작업을 동시에 수행할 수 있게 해줍니다.
✅ 특징
- 효율성: 사용자는 요청에 대한 응답을 기다리는 동안 다른 작업을 진행할 수 있어, 시스템 자원을 효율적으로 활용할 수 있습니다.
- 복잡성: 비동기 처리에서는 결과가 언제 돌아올지 예측할 수 없기 때문에, 코드의 복잡성이 증가할 수 있습니다. 예를 들어, 콜백(callback)이나 프라미스(promise) 같은 추가적인 구조가 필요합니다.
비동기는 웹 애플리케이션이나 서버-클라이언트 모델에서 자주 사용되며, 사용자 경험을 개선하고 시스템의 응답성을 높이는 데 효과적입니다.
📍 콜백 지옥이란?
비동기 프로그래밍에서는 서버로부터의 응답을 기다리는 동안 다른 작업을 수행할 수 있는 유연성을 제공합니다. 그러나 이 과정에서 자주 발생하는 문제 중 하나가 바로 콜백 지옥(Callback Hell)입니다.
콜백 지옥은 여러 개의 비동기 작업이 중첩되어 복잡한 구조를 이루게 되는 상황을 말합니다.
비동기 함수가 다른 비동기 함수의 결과를 처리하기 위해 콜백 함수를 사용하게 되면, 코드가 들여쓰기가 깊어지고 읽기 어려워집니다. 이러한 구조는 유지보수와 디버깅을 어렵게 만들며, 코드의 가독성을 저하시킵니다.
다음은 콜백 지옥의 간단한 예시입니다.
getData(function(result) {
processData(result, function(processedData) {
saveData(processedData, function() {
console.log('Data saved successfully!');
});
});
});
위의 코드에서 각 비동기 작업이 완료된 후 다음 작업을 수행하기 위해 계속해서 콜백 함수를 중첩해야 하므로, 코드가 점점 복잡해집니다. 이러한 중첩은 "지옥"이라는 표현이 사용될 만큼 가독성을 떨어뜨립니다.
✔️ 콜백 지옥의 원인
콜백 지옥은 주로 다음과 같은 이유로 발생합니다:
- 비동기 처리의 특성: 비동기 작업이 완료될 때까지 기다리지 않고 다음 작업을 수행하기 때문에, 결과를 처리하기 위해 중첩된 콜백이 필요합니다.
- 비즈니스 로직의 복잡성: 복잡한 비즈니스 로직을 여러 비동기 작업으로 나눌 때, 각 작업의 결과를 처리하기 위해 콜백을 계속 중첩해야 합니다.
💡 콜백 지옥 해결 방법
1️⃣ 프라미스(Promise) 사용
프라미스를 사용하면 비동기 작업의 결과를 보다 간결하게 처리할 수 있습니다. 체이닝을 통해 가독성을 높이고, 에러 처리도 간편해집니다.
getData()
.then(processData)
.then(saveData)
.then(() => {
console.log('Data saved successfully!');
})
.catch(error => {
console.error('Error:', error);
});
2️⃣ async/await 사용
async/await 구문은 비동기 코드를 동기 코드처럼 작성할 수 있게 해줍니다. 이를 통해 콜백 지옥을 피할 수 있습니다.
async function handleData() {
try {
const data = await getData();
const processedData = await processData(data);
await saveData(processedData);
console.log('Data saved successfully!');
} catch (error) {
console.error('Error:', error);
}
}
이처럼 프라미스나 async/await와 같은 방법을 사용하여 이러한 문제를 해결할 수 있으며, 더 깔끔하고 이해하기 쉬운 코드를 작성할 수 있습니다. 비동기 프로그래밍의 이점을 최대한 활용하기 위해, 콜백 지옥을 피하는 방법을 숙지해 두는 것이 중요합니다.
⭐ 블록(Block)과 논블록(Non-block)
블록과 논블록은 동기와 비동기의 개념과 밀접하게 연결되어 있습니다.
✅ 블록
블록은 동기 처리에서 나타나는 상태로, 계속 대기해야 하는 상태를 의미합니다.
예를 들어, 데이터 요청을 보내고 결과를 기다리는 동안, 해당 스레드는 다른 작업을 수행할 수 없습니다.
블록 상태에서 프로그램은 요청의 완료를 기다리므로, 시스템의 효율성이 떨어질 수 있습니다.
✅ 논블록
논블록은 비동기 처리에서 나타나는 상태로, 요청 후 대기하지 않고 자유롭게 사용할 수 있는 상황을 의미합니다.
사용자는 서버의 응답을 기다리는 동안 다른 작업을 수행할 수 있으며, 이를 통해 시스템의 자원을 효과적으로 활용할 수 있습니다.
🚩 결론
동기와 비동기는 소프트웨어 개발에서 매우 중요한 개념으로, 각각의 특성과 활용 방법을 이해하는 것이 필요합니다.
블록과 논블록의 개념도 이러한 동작 방식과 밀접하게 연결되어 있으며, 시스템 아키텍처 설계 시 매우 중요한 요소로 작용합니다.
'기술 지식 쌓아가기 📚 > Backend 🍔' 카테고리의 다른 글
[DB] 동시성 문제 해결을 위한 다양한 접근법 (3) | 2024.10.13 |
---|---|
[시스템 아키텍처] CI/CD 오케스트레이션: Docker, Jenkins, Kubernetes의 조화로운 협력 (0) | 2024.10.13 |
[DB] JPA와 ORM: 데이터베이스와의 스마트한 연결 (0) | 2024.10.08 |
[DB] Spring에서의 데이터베이스 처리: JDBC vs JPA (0) | 2024.10.08 |
[DB] 데이터베이스와의 상호작용을 쉽게 만드는 DAO 패턴 (+ DTO까지!) (3) | 2024.10.07 |