221102 생산적인 삽질을 위하여. 프로그래머스 짝지어 제거하기(자바)

샨티(shanti)·2022년 11월 2일
0

하루를 마무리 하기 전, 오늘 있었던 일들을 잔잔히 되짚어봅니다.
성공과 실패의 모든 요소에서 '배울 점'을 찾아내어 기록하고,
더 성장하는 내일의 나를 위해 'action plan'을 세웁니다.

말이 좀 웃기기는 하지만ㅎㅎ
요즘은 삽질도 생산적으로 하고자 노력중인 것 같다. 사실 내가 알아서 노력하기에는 방법을 잘 모르기에 트레이너님들의 가이드를 따라가는 중인데 그 과정에서 필연적으로 발생하는 '삽질'의 시간이 있다. 좀 더 고급지게는 '시행 착오의 시간'이라고 얘기할 수 있을 것이다.

어제는 <select>, <option> 문제 때문에 정말 온전-히 하루를 꼬박 날렸고 오늘은 답을 확인하니 너무나도 심-플한 코딩도장 문제로 오랜 시간을 투입했다.

전자는 노아님께 sos를 치고 피드백을 받으면서, 그리고 후자는 작성하다가 해결하지 못한 내 답안과 타인의 답안을 비교하며 해결하게 되었다.
그저 '안풀리던게 풀렸네?' 하고 끝난다면 말 그대로 '삽질'에서 그치겠지만, 생산적으로. 즉 그 삽질의 결과가 나를 한 뼘이라도 자라게 하기 위해서는 노아님이 항상 이야기하던 '굳이'가 필요하다.

그래서 작성해보는 오늘의 코딩도장 '굳이'.

문제: 프로그래머스 짝지어 제거하기

문제는 링크를 참고. 아래는 제출 답안이다.

import java.util.*;

class Solution {
  public int solution(String s) {
    int answer = -1;

    Stack<Character> stack = new Stack<>();

    // start
    stack.push(s.charAt(0));
    int count = 0;

    // process
    for (int i = 1; i < s.length(); i += 1) {
      char selectedCharacter = s.charAt(i);

      // 스택이 비어있을 땐 무조건 들어가야 함
      if (stack.empty()) {
        stack.push(selectedCharacter);
        continue;
      }

      if (!stack.empty()) {
        // 스택이 비어있지 않으면서 스택의 가장 마지막 요소가 현재 요소와 같으면 맨 위에거 빼기
        if (stack.peek() == selectedCharacter) {
          stack.pop();
          continue;
        }

        // 스택이 비어있지 않으면서 스택의 가장 마지막 요소가 현재 요소와 다르면 집어넣기
        if (stack.peek() != selectedCharacter) {
          stack.push(selectedCharacter);
        }
      }
    }
    return stack.empty() ? 1 : 0;
  }
}

문제를 읽자마자 예전에 풀었던 카카오 기출 크레인 인형뽑기 문제가 생각났다. 그 떄 정말 극악 난이도라고 느꼈고 결국엔 풀지 못했던 기억이... 풀지 못한건 물론이거니와 추석 연휴 1주일 동안 같은 문제를 반복해서 풀어보려고 했었지만 테스트코드로 작은 단위에서 시작하는 것 조차 하지 못했던 기억이 난다.

하지만 홀맨님이 제공해주셨던 코딩도장 훈련 포맷에 보면 '반성' 파트에 과거의 경험에서 이후에 적용할 것을 추출하는 것이 있는데 이를 오늘 문제 풀이에 적용했던 것 같다. 비록 크레인 문제는 과거에 풀지 못했으나, (1) 유사한 패턴의 문제임을 파악했고, (2) 당시에 별도로 공부했던 스택(또는 큐)을 떠올렸기 때문이다.

결정적으로 해결하지 못했던 이유

방향성도 맞게 설정했고 정답에 근접했음에도 불구하고 왜 주어진 시간 내에 풀지 못했는가?

고질적인 문제인 것 같은데..
(1) 너무 많은 경우의 수를 생각하는데
(2) 이를 순서대로(즉 테스트코드로) 증명하지 않은 채
(3) 한번에 해결하려다보니

이 삼박자가 맞으면서 잘 해결이 안되는 것 같다.
오늘 초반에 작성한 코드 일부를 가져왔는데 살펴보면 그렇다.

// 일부 발췌
  if (!stack.empty()) {
        // 스택이 비어있지 않으면서 스택의 가장 마지막 요소가 현재 요소와 같지 않으면 들어가기
        if (stack.peek() != selectedCharacter) {
          stack.push(selectedCharacter);
          continue;
        }

          if (i + 1 == s.length()) {
            if (stack.peek() == selectedCharacter) {
              stack.pop();
              break;
            }
          }

아주 단순하게, 스택에 하나씩 넣어가면서 겹치는 순간에 빼면 되는데, 나는 그 단계를 하나 더 뛰어넘어, '그렇담 그 다음에 또 똑같은 문자가 나오면 2개가 아니라 3개가 중복되는 것이니 없앨수가 없겠네..? 그것도 고려를 해야하네?' 로 이어지며... 생각이 멈춤.

지금도 명쾌하게 이해되지 않는 부분은 있다. 하지만 주어진 예시보다 좀 더 많은 테스트코드로 단순한 반복을 계속 해봤으면 적어도 오늘 오전처럼 못 풀진 않았겠다는 반성.


두 번째 회고. 객체 생각하기

동료들이 요즘 계속 1:N, N:1을 이야기하며 무언가를 계속 토론하고 있을 때, 지도 API랑 씨름아닌 씨름을 하고 있자니 약간 외로운(ㅋㅋㅋㅋ) 마음이 들었다.

한편으론 '아, 함께 일할 동료가 없는, 같은 주제로 토론하고 또 공부할 동료가 없는 회사에 가게 되면 정-말 심심하고 외롭겠다'는 생각도 들었다.

오늘은 프론트쪽이 잘 해결되지 않아 백엔드를 살펴보면서 객체 모델에 대해 고민해보기로 했다.
별 것 아닌 새로운 시도이지만 동료에게 다이어그램 만드는 페이지도 공유받아서 첨으로 써보고.. 이번 프로젝트를 준비하면서 소소하지만 새롭게 시도해보는 것들이 꽤 많은 것 같다.

아래는 아직 완벽하게 구상한 것은 아니지만 '장소'라는 객체와 그 하위에 들어가는 일부 객체들을 시각화 시켜본 것.

이대로 만들어서 서버를 돌려보니 계속 id를 찾을 수 없다고 에러가 나는 상태라 일시정지 해두었다.

객체모델을 구상하는 것이 어렵다고는 알고 있었는데 곱씹을수록 쉽지 않은 것 같다.
예전 같았으면 내가 필요한 항목들에 대해 숫자면 Long, 문자면 String으로 다 때려넣는 방법을 택했을텐데.

요즘은 '협력'이란 단어를 고려하지 않을 수 없다.
객체들 간의 협력. DB를 먼저 생각하는 것이 아니라 바르게 만들어진 객체 모델과 그 객체들간의 협력을 먼저 구상한 뒤 DB에 넣는 것은 나중에 이루어지는 일이 되는 것.

사실 어떻게든 DB 컬럼에 맞추고 빈틈없이(ㅎㅎ) 데이터를 집어 넣는 것부터 시작하려는 습관이 남아있는데...
지난번에 홀맨님이 도장에 오셔서 말씀해주신 내용을 메모해두고 오늘 모델을 설계하기 전 여러번 읽어보니 위에서 말한 순서가 지켜지지 않으면 모델은 서비스가 완성될 때까지 흔들흔들. 자리잡지 못하고 수정을 반복하게 될 것 같다는 생각이 들었다.

결국 객체를 설계하는 시간, 그리고 그 설계한 객체가 최적이고 최선의 방향은 아닐지 모르겠지만 결국 경험이 부족한 나로서는 삽질의 시간을 최대한 생산적이고 성장의 밑거름으로 만들어야 한다는 생각이 들었다.

이번주 남은 태스크가 너무 많아 압박도 있고, 또 금방 해결되지 않을 것들이라 답답하기도 하지만 매일이 교훈이 되어 성장하는 내일을 기약할 수 있도록 해야겠다.

profile
가벼운 사진, 그렇지 못한 글

0개의 댓글