@@ -0,0 +1,126 @@
+package codesquad.qua;
+
+import codesquad.answer.Answer;
+import codesquad.exception.QuestionDeleteException;
+import codesquad.exception.QuestionEditException;
+import codesquad.user.User;
+import codesquad.utils.SessionUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpSession;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class QuestionService {
+
+    private final QuestionRepository questionRepository;
+
+    public boolean setCreateForm(HttpSession session) {
+        User user = SessionUtil.getUserBySession(session);
+
+        return user != null;
+    }
+
+    public boolean create(QuestionDto questionDto, HttpSession session) {
+        log.info("작성자 = {}", questionDto.getWriter());
+        log.info("제목 = {}", questionDto.getTitle());
+
+        User user = SessionUtil.getUserBySession(session);
+
+        if (user == null) {
+            return false;
+        }
+
+        questionRepository.save(new Question(questionDto, user));
+
+        return true;
+    }
+
+    public List<Question> list() {
+        return questionRepository.findAll();
+    }
+
+    public void setUpdateForm(long id, HttpSession session) {
+        User user = SessionUtil.getUserBySession(session);
+        Question savedQuestion = findQuestionById(id);
+
+        if (user == null || !isQuestionMatchUser(user, savedQuestion)) {
+            throw new QuestionEditException();
+        }
+
+        log.info("user: {}", user.getName());
+        log.info("question: {}", savedQuestion.getWriter());
+    }
+
+    @Transactional
+    public void update(QuestionDto changedQuestion, long id, HttpSession session) {
+        User user = SessionUtil.getUserBySession(session);
+        Question savedQuestion = findQuestionById(id);
+
+        if (user == null || !isQuestionMatchUser(user, savedQuestion)) {
+            throw new QuestionEditException();
+        }
+
+        log.info("user: {}", user.getName());
+        log.info("question content: {}", changedQuestion.getContents());
+        log.info("question title: {}", changedQuestion.getTitle());
+
+        savedQuestion.update(changedQuestion);
+    }
+
+    @Transactional
+    public void remove(long id, HttpSession session) {
+        User user = SessionUtil.getUserBySession(session);
+        Question savedQuestion = findQuestionById(id);
+
+        log.info("user: {}", user.getName());
+        log.info("question: {}", savedQuestion.getWriter());
+
+        if (user == null || !isQuestionMatchUser(user, savedQuestion)) {
+            throw new QuestionEditException();
+        }
+
+        if (!canDeleteQuestion(savedQuestion, user)) {
+            throw new QuestionDeleteException();
+        }
+
+        savedQuestion.deleteQuestion();
+    }
+
+    public long countAnswers(long questionId) {
+        Long countAnswer = questionRepository.countNotDeletedAnswers(questionId);
+
+        if (countAnswer == null) {
+            return 0L;
+        }
+
+        return countAnswer;
+    }
+
+    public Question findQuestionById(Long id) {
+        return questionRepository.findById(id)
+                                 .orElseThrow(NoSuchElementException::new);
+    }
+
+    private boolean canDeleteQuestion(Question deletedQuestion, User user) {
+        if (deletedQuestion.hasAnswers()) {
+            for (Answer answer : deletedQuestion.getAnswers()) {
+                if (!answer.equalsWriter(user)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean isQuestionMatchUser(User loginUser, Question question) {
+        log.info("match User? = {}", question.equalsWriter(loginUser));
+        return question.equalsWriter(loginUser);
+    }
+}

리뷰: canDeleteQuestion은 질문을 삭제할 수 있는지 판단하는 메서드입니다
- 답글이 없을 경우 삭제 가능
- 답글이 있으나 작성자 모두 질문 작성자와 같을 경우 삭제 가능

해당 메서드는 Question이 삭제될 수 있어?라고 묻고, Question이 삭제될 수 있어/없어를 판단합니다
그래서 저는 이 부분이 Question에게 물어보고 Question이 결정하는 것이라는 생각이 들어 Question 클래스에 있어야할까라는 생각을 했습니다.

하지만 이 논리라면 아래 isQuestionMatchUser(질문 작성자와 로그인 된 User가 같은지 판단하는 메서드)도 Question에 있어야하지 않을까라는 생각을 했지만, 그렇게 되면 Question 클래스가 너무 무거워지지 않을까라는 생각도 들었습니다

리뷰어님은 어떻게 생각하시는지 궁금해서 comment 남겨봅니다!