250518

Regular Kim·2025년 5월 18일

회고

목록 보기
91/115

250518 회고 💬

5월도 중순이 지났다. SSAFY에서는 VUE.js를 배우고 있다. 입과 전에 예습한다고 개념 공부도 하고, 프로젝트도 만들었었다. 그리고 모두 까먹었다. 💀 늘 새로운 프론트의 세계.... 5월의 셋째 주를 되돌아본다.

Keep 👍

알고리즘

알고리즘 문제 풀이를 계속 하고있다. 그날그날 기분따라서 아무 주제나 잡고 문제를 푼다.

  • 치즈 : 간단한 BFS 문제를 풀었다. 골드 3 난이도여서 많이 어려울 듯 싶지만 기본기만 튼튼하다면 실버 문제 마냥 쉽게 풀 수 있는 문제다.
  • 타임머신 : 벨만-포드 알고리즘을 공부했다.
  • 웜홀 : 벨만-포드 알고리즘을 복습 문제다. 복습 문제라기엔 어려웠다. 그래프 개념을 다시 생각해보는 시간이었다.

출퇴근 자투리 공부

동영상 공유 플랫폼을 제작하고 있기 때문에 기본적인 기능들을 어떻게 구현하나 평소 궁금했었다. 게다가 혼자 할 때는 괜찮지만 실제 사용자가 생기면 어떤 일이 생길지 모르기 때문에 성능 최적화 등에도 관심이 있었다. 그래서 관련 기술과 최적화를 설명해주는 강의를 듣고 있다.

  • 도커로 구동 환경 분리하기
  • 레디스로 조회수 구현하기
  • 카프카로 인기글 구현하기

개인 공부

개인 프로젝트에 집중해서 시간을 할애하고 있다. 이번 주에는 테스트 코드 작성에 신경을 썼다. 저번 주에 리팩토링을 하면서 클래스가 많이 늘어났다. 반면에 실제 구동은 해피케이스로만 진행해서 눈감고 길을 걷는 것 마냥 위태로운 상태가 됐다. 유틸, 리졸버, 핸들러 등등 만들어놓은 클래스마다 테스트 코드를 작성하고 있다.

  • 유저 도메인 테스트 작성
  • 비디오 도메인 테스트 작성

테스트 코드를 작성하면서 느끼는 점은 여러가지가 있지만 가장먼저 말하자면 '귀찮다'이다. 😖 너무 귀찮다. 단순히 계산을 해봐도 내가 작성하는 모든 메서드를 한번씩은 검사를 해봐야 하므로 처리할 일이 2배 넘게 늘어난다. 그럼에도 왜 이런 귀찮은 일을 하냐 하면,,, 테스트 코드 작성을 하면서 동시에 코드 구조 개선이 이루어지기 때문이다. 큰 작업을 혼자 맡아 처리하던 클래스를 테스트하다보면 부분부분을 나눠야겠다는 생각이 저절도 든다. 그러면서 메서드 호출 구조를 신경쓰게 되고, 그러면서 객체지향적으로 접근하게 되고 등등등 귀찮더라도 꼭 해야하는 작업(테스트 코드를 작성할 수 없을 만큼 급박한 일정에서는 어찌해야할지 모르겠지만)이라는 생각을 하고있다.

테스트 코드를 작성하면서 UUID 같이 값을 컨트롤할 수 없는 부분이 계속 방해가 되었다. 그래서 이 부분을 개선하기 위한 방안을 정리해봤다. 글은 여기서 확인할 수 있다.

어느정도 프로젝트가 진행됐다고 착각했었다... 포트폴리오 작성하려고 진행한 내용을 정리해봤는데 너무 초라한 프로젝트임을 알게되었다. 몇몇 기능들을 더 넣으려고 한다. 가장 먼저 oauth2 가 생각이 났다. 기능 구현 전에 관련 내용들을 좀 정리해봤다. 내용은 여기서 볼 수 있다.

독서

<한 권으로 읽는 컴퓨터 구조와 프로그래밍>을 계속 읽고 있다.

Try 🧚

  • 매일 골드 이상 난의도의 알고리즘 문제 풀이 진행하기
  • 개인 프로젝트 진행하기
    - 백엔드
    - 레스트 독스 구현
    - 테스트 코드 고도화
    - 내장 h2 DB에서 MySQL로 데이터베이스 전환
  • 최소 1곳 이상 회사 지원하기
    - 이력서
    - 포트폴리오
  • 책읽기 다시 시작하기
  • msa, 도커, 카프카 공부 시작하기

독서 목록

서평 완료 목록

서평 예정 목록 (읽는 중)

  • 면접을 위한 CS 전공지식 노트
  • 한 권으로 읽는 컴퓨터 구조와 프로그래밍

독서 예정 목록

  • 오브젝트
  • HTTP 완벽 가이드
  • 자바/스프링 개발자를 위한 실용주의 프로그래밍
  • 모던 자바 인 액션
  • 자바 성능 튜닝 이야기
  • 헤드 퍼스트 서블릿
  • 파이브 라인스 오브 코드

Extras 🧑‍💻

치즈


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    
    public static void main(String[] args) {
        new Main().run();
    }

    private void run() {
        System.out.println(new Solution().solution(readInput()));
    }

    private int[][] readInput() {
        try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {

            StringTokenizer st = new StringTokenizer(br.readLine());
            int height = Integer.parseInt(st.nextToken());
            int width = Integer.parseInt(st.nextToken());

            int[][] field = new int[height][width];

            for(int i = 0; i < height; i++) {
                st = new StringTokenizer(br.readLine());
                for(int j = 0; j < width; j++) {
                    field[i][j] = Integer.parseInt(st.nextToken());
                }
            }

            return field;
        }catch(IOException e) {
            throw new RuntimeException();
        }
    }
}

class Solution {

    private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

    private int[][] field;
    private boolean[][] isOutside;
    private Queue<int[]> cheeseQ;
    private Queue<int[]> meltTargets;
    private int result;

    public int solution(int[][] field) {
        init(field);
        calc();
        return result;
    }

    private void init(int[][] field) {
        this.field = field;
        this.isOutside = new boolean[field.length][field[0].length];
        this.cheeseQ = new ArrayDeque<>();
        this.result = 0;

        for(int i = 0; i < field.length; i++) {
            for(int j = 0; j < field[i].length; j++) {
                if(field[i][j] == 0) continue;
                cheeseQ.offer(new int[] {i, j});
            }
        }
    }

    private void calc() {
        while(!cheeseQ.isEmpty()) {
            checkOutside();
            searchMeltCheeses();
            melt();
            result++;
        }
    }

    private void checkOutside() {
        this.isOutside = new boolean[field.length][field[0].length];
        Queue<int[]> q = new ArrayDeque<>();
        q.offer(new int[] {0, 0});
        isOutside[0][0] = true;

        while(!q.isEmpty()) {
            int[] cur = q.poll();

            for(int[] d : DIRECTIONS) {
                int nx = cur[0] + d[0];
                int ny = cur[1] + d[1];

                if(out(nx, ny)) continue;
                if(field[nx][ny] != 0) continue;
                if(isOutside[nx][ny]) continue;

                isOutside[nx][ny] = true;
                q.offer(new int[] {nx, ny});
            }
        }
    }

    private void searchMeltCheeses() {
        Queue<int[]> meltCandidate = new ArrayDeque<>();
        Queue<int[]> newCheeses = new ArrayDeque<>();

        while(!cheeseQ.isEmpty()) {
            int[] cheese = cheeseQ.poll();

            if(isMeltTarget(cheese)) meltCandidate.offer(cheese);
            else newCheeses.offer(cheese);
        }

        this.meltTargets = meltCandidate;
        this.cheeseQ = newCheeses;
    }

    private void melt() {
        while(!meltTargets.isEmpty()) {
            int[] cur = meltTargets.poll();
            field[cur[0]][cur[1]] = 0;
        }
    }


    private boolean out(int x, int y) {
        return field.length <= x || x < 0 || field[x].length <= y || y < 0;
    }

    private boolean isMeltTarget(int[] cheese) {
        int cnt = 0;
        for(int[] d : DIRECTIONS) {
            int nx = cheese[0] + d[0];
            int ny = cheese[1] + d[1];

            if(out(nx, ny)) continue;
            if(isOutside[nx][ny]) cnt++;
        }

        return cnt >= 2;
    }
}
profile
What doesn't kill you, makes you stronger

0개의 댓글