20210630

Jin·2021년 6월 30일

계획

  • 가장 긴 팰린드롬 문제 - 스칼라의 꼬리재귀 지원을 활용해서 백트래킹 풀이의 유효성을 검증한다.

  • 리팩토링 책 읽기 - 지침이 여러가지 있어서 산만해지는데, 몇가지를 골라서 깊이있게 이해하는 것이 좋을까?https://programmers.co.kr/learn/courses/30/lessons/70128

  • 그림으로 배우는 http 배운 내용 정리, 부가 정리 -> 세션, 쿠키, 바이트 스트림

지침

  • 무엇이 안되는지 보다, 무엇이 되고 싶은지와 무엇을 연습하고 싶은지에 주목하라.
  • 내가 하는 일들을, 지배 속에 넣어라.

Facts

프로그래머스 <내적> 풀기

문제: https://programmers.co.kr/learn/courses/30/lessons/70128
풀이: https://github.com/gringrape/daily_coding_dojo/tree/main/20210630/javascript

프로그래머스 <가장 긴 팰린드롬> 풀기

문제: https://programmers.co.kr/learn/courses/30/lessons/12904

시작과 끝을 가리키는 두개의 포인터를 이용해서 풀었다. 백트래킹 방식의 재귀로 풀었는데,
코어 덤프 오류가 났고, 시간초과가 되는 케이스도 두개 존재했다.

향후과제는, 일단, 이 방식의 유효성을 검증하기 위해서 스칼라의 꼬리재귀 지원 기능을 이용해서 풀어보고, 작동을 잘한다면 이 방식을 반복문을 사용해서 다시 처리하고, 아니라면, 다른 방식으로 풀어야 겠다.

또 한가지 생각해야 할것은 분명 백트랙킹이라고 생각했는데, 백되는 과정에서 중복되는 연산이 너무 많이 존재한다는 점이다. 메모이제이션을 적용해서 어떻게 풀 수 있는지도 생각해보아야 할 것 같다.


꼬리재귀 최적화는 지원되지 않았다. 재귀함수의 호출이 함수 끝에 존재하는 경우에만 지원하는 것이었다.

동적프로그래밍으로 풀기 위해서 점화식을 세웠다.

리팩터링 읽기

  • 2장 - 리팩토링 원칙 - 코드의 작동성을 유지하면서 리팩토링한다.
  • 3장 - 코드에서 나는 악취 - 악취의 여러가지 패턴을 알아본다.
  • 4장 - 테스트 - 픽스처, 속성, 검증

테스트 주도 개발의 흐름에 익숙해지면 디버깅하는 시간이 크게 줄어든다. 소프트웨어 개발에서 시간이 오래 걸리는 부분 중 하나는 버그를 찾는 디버깅 과정이다. 버그를 해결하는 것은 시간이 오래 걸리지 않는다. 문제는 버그의 원인이 무엇인지 찾아내는 과정이다.

HTTP 공부

  • HTTP 엔티티 - 멀티파트, 레인지, 청크
  • HTTP 상태코드 - 403 과 401 의 차이, 206, 3xx 번의 일반적 의미
  • 게이트웨이와 터널
  • 프록시 - 캐싱, 액세스 제어
  • 호스트네임과 도메인이름

게이트웨이라고 하는 용어에 대해서 생각해보았다. 전송 프로토콜이 달라질때(HTTP >> ??) 중간에 있는 녀석이었는데, 이용어는 이전에도 등장한적이 있다. 네트워크의 경계에서 다른 네트워크로 데이터를 전송할때, 초기에 MAC 주소로 기본 게이트웨이를 지정한다. 이 게이트웨이라고 하는 것이 하나의 영역에서 그것과 일치하지 않는 다른 영역으로 가는 느낌이라고 이해했다.

사전적 정의로는 무엇이든지 어떤 영역의 입구를 말하며, 네트워크에서는 네트워크의 경계에 위치한 컴퓨터를 뜻한다고 한다.

프로그래머스 <키패드 누르기> 풀이

문제: https://programmers.co.kr/learn/courses/30/lessons/67256
풀이: https://github.com/gringrape/daily_coding_dojo/pull/24

비틀어서 구현하지 않기쓰는쪽 부터 만들기를 실천했던 문제였다. 부가적으로 비교적 단순한 케이스부터 학습하며 구현을 발전시켜 나가는 것도 의식적으로 실천했는데, 저녁 스터디에서 윤석님도 그렇게 하고 계셔서 공감이 많이 되었다.

손의 위치를 업데이트 하는 상태 업데이트가 활용되는 문제였다. 나는 객체형식의 데이터를 지정해서 사이드 이펙트를 활용하는 방식으로 풀었다. 데이터의 사이드 이펙트를 적용할때는 클래스의 활용을 고려해보아야겠다. 캡슐화와 자료 안정성 측면에서 훨씬 나은 선택인것같다.

관심사의 분리는 어설펐다. 가까운 손을 찾는 함수와 누르는 함수에서 중복 로직이 발생했다. 리팩토링 모자를 쓰는 시간을 더 확보해야 할까?

Feelings

리팩토링

리팩토링 책을 읽으면서 많은 걸 생각한 하루였다. 결국 무언가를 개선하기 쉬우려면 어떤 조건을 만족해야하는가에 대한 생각을 하면서 읽었다.

과제의 양이 중요하다. 사실 중요한 건 해당 과제에서 해결해야할 관심사의 개수인것 같긴 하지만, 어쨌든 양을 통제하면 자연스럽게 통제되는 부분인것 같다. 주의를 잃지않으면서, 의도를 반영할 수 있는 사이즈가 굉장히 중요하다.

의도가 중요하다. 누구나 어떤 행동을 하든 의도는 있다. 하지만, 의도이 있어서 문제가 되는 것 같다. 여러가지 의도가 혼재되어서 혼란을 낳고 결국은 하나의 의도도 실현되지 못한다. 한번에 하나의 의도가 중요하다.

피드백이 중요하다. 의도와 현실사이에는 간극이 존재한다. 통제가능한 범위와 의도하에서 이 간극을 아주 정확하게 알아채고(이게 중요한 것 같다.) 고쳐야 한다. 알아채기 위해서는 명확해야 한다.

좋은 습관

아샬이 어떻게 하셨었는지 계속 복기해보고 있는데 엄청 도움이 된다. 최근에 실천해보고 있는것은 뭔가를 비틀어서 해결하지 않는 것이다. 이게 표현하기가 조금 힘든데, 라이브러리를 사용하든, 보편적인 지식을 활용하든 아주 일반적이고 평이한 인터페이스, 부분을 활용해서 문제를 해결한다는 것이다.

뭐랄까.. 젓가락을 젓가락처럼 쓴다고 해야할까? 젓가락을 구부려서 쓰기 보다 구부릴 일이 있으면 다른 도구를 사용한다. 해당도구의 가장 잘 만들어진 부분을 활용한다고도 생각해볼 수 있겠다.

이외에도 다 되는 상태에서 시작하기, 쓰는 쪽부터 만들기, 작업환경을 지배하기, 기계적으로 하지 않기 등등의 시리즈가 있다.

Findings

꼬리재귀

다음 코드는 꼬리재귀 최적화가 지원되지 않는다
.

  def solution(s: String): Int = {
    var results = List[Int]()

    def go(start: Int = 0, end: Int = s.length() - 1, count: Int = 0): Unit = {
      if (start > end) {
        results = count :: results
        return
      }

      if (start == end) {
        results = (count + 1) :: results
        return
      }

      if (s.charAt(start) == s.charAt(end)) {
        go(start + 1, end - 1, count + 2)
        return
      }

      go(start + 1, end)
      go(start, end - 1)
      go(start + 1, end - 1)
    }

    go()

    results.max
  }

Feelings

나는 나를 신뢰한다.

0개의 댓글