Posts

Showing posts from 2021

프로젝트를 진행할때 반드시 읽어볼 것(시작할때, 중간중간 매일 일할때도)

성장을 해야한다. 시간이 지날수록, 경력 기간이 늘어날수록, 실력도 증가해야 한다. 단순히 시간이 지난다고 해서 실력도 발전하진 않는다. 여태까지 그랬다. 시간을 어마어마하게 쏟아부으면, 당연히 없던 실력에선 어느정도 발전이 있을수밖에 없지만. 어느새부턴가 단순반복이 되어버리면, 배움도 없고 발전하지 못한다.   회고의 중요성 실력이 증가하려면 시간과 경험이 일단 쌓여야하지만, 무언가 일단락 되었을때 되돌아봐야만 한다. 늘 언제나 there is a room for an improvement 이다. 언제나 항상. 그리고 여태까지 나는 이  과정이 없었기 때문에 더 발전하고 고칠 수 있었음에도 불구하고 잘못을 답습해왔다. 실수도 반복되면 실력이라고. 내가 더 발전하지 못한 가장 큰 이유중 하나는 회고하고, 되돌아보고, 복기하지 않는다는 것이다. 의미있는 회고가 되려면 제일 중요한건 시작하기 전에 계획이 있어야 한다. 계획이 없이 열심히만 했으면. 회고할때 뭘 잘했고 뭘 잘못했으며 다음번에 다시하게 되면 어떻게 더 잘 할수 있을지를 파악하지 못한다. 그저 그 순간순간 밤새 열심히 했다, 밖에 남지 않아버리면. 다음에도 똑같이 반복할 수밖에 없다. 계획을 잘 짜려면 프로젝트 특성상 deadline 단위로 끊을수밖에 없다. 계획이라는게 결국은 일정관리아닌가. 언제까지 뭘 하겠다가 큰 그림이고. 그럼 backward 로 잘라가면서 milestone 별로 break down 해야한다. 그렇게 언제까지 뭐가 되고, 언제까지 뭐가 되고가 나온다. 그럼 나중에 프로젝트다 끝나고 나면 일정 을 짤때 놓친 부분이 나오고, 다음번 프로젝트에 이를 고려한 일정을 계획할 수 있다. 개발이 다가 아니다 아직까지 고치지 못하는 버릇. 내 부분만 하면 끝난다는 생각. 나머지는 신경도 안쓰고 무책임해버린다. 서버개발은 되었어도 프론트가 안되었으면 테스트를 할수 없다. 개발 자체가 물론 중요하고 개발이 안되면 프로젝트가 망하지만. 일정과 전체적인 진행상황, 일을 제때 제대로 되...

Hibernate cache 에 대해서. 그리고 merge, refresh

 우선 Hibernate 는 1차, 2차 cache 를 제공한다.  1차는 기본적으로 default enabled 되어 있다. 임의로 disable 시킬 수 없다. session 별로 caching 이 유지되며, session 이 close 되면 이에 따라 cache 정보도 날라간다. 2차는 기본적으로 disabled 되어 있다. sessionFactory 단위의 caching 이기때문에 모든 session 에 적용이 된다. Hiberante 자체에서 제공하는게 아니고, ehcache 등 제 3의 memory cache 를 provide  해줘야 하는 모양이다. 그럼 DB 에 임의 로 접근해서 정보를 바꾸거나 지워버리면, Hibernate cache는 어떻게 될까? 이 외부적인 요인에 의한 변경을, hibernate 가 알 방법은 없다.  그렇기 때문에 cache 가 업데이트 되지않는다. merge 혹은 refresh  를 해줘야 하는데, merge : 현재 session entity 가  가지고 있는 데이터를 DB 에 쓴다.  refresh : 현재 DB 에 있는 정보를 session entity 로 가지고 온다. 혹은 기존 session 들에 대해서  아래와 같이 evict  를 호출함으로써, entity 가 다시 불려질때 query 를 통해 최신 정보를 가져오게 할 수있다. org.hibernate.Cache.evictAllRegions() 참조링크 https://howtodoinjava.com/hibernate/understanding-hibernate-first-level-cache-with-example/ https://stackoverflow.com/questions/2461063/how-to-clear-all-hibernate-cache-ehcache-using-spring

EnumMap vs HashMap, 그리고 InteruptedException

회사 동료의 코드리뷰 중 HashMap 을 EnumMap 으로 바꾼 부분을 보고 찾아봤다. EnumMap 은 사실 처음보는거 같은데 . JavaDoc 에 의하면 Enum maps are represented internally as arrays. This representation is extremely compact and efficient. Implementation note: All basic operations execute in constant time. They are likely (though not guaranteed) to be faster than their HashMap counterparts. 이라고 한다. JavaDoc 에서 extremely compact and efficient 라고 표현을 하다니. Map 의 K,V 에서 Key 부분의 타입이 Enum 인 경우에는 반드시 EnumMap 을 쓰도록 해야겠다.

168. Excel Sheet Column Title

난이도는  Easy 인데, Acceptance 는 32% 여서, 뭐지 하고 봤다. 처음엔 쉽게 봤는데, 결국 못풀었다. 26진수나 마찬가지라고 생각해서, % 와 / 연산을 사용했는데. 접근이 비슷하긴 했는데 아주 틀렸다. 문제에서 주어지기로는 A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 이런식으로 주어졌다.  문제는, 26진수라고 했을때, 1에서 26까지 가는걸 A 에서 Z 까지 간다고 생각할 수는 있는데,  0이 없다.  10진수의 경우, 0부터 시작해서 9까지 간 다음, 10 으로 가는데. 이건 시작이 1이다. 일반적인 26진수라면  0 -> A 1 -> B 25 -> Z 26 -> BA (= B*26+A*1) 27 -> BB (= B*26+B*1) 이런식으로 간다. 그런데 위의 경우에는 1 -> A 2 -> B 26 -> Z 27 -> AA (= A*26+A*1) 28 -> AB (= A*26+B*1) 이와같이 움직였다. 1,2,3,... 9 다음에 10이 아닌 11이 오는거나 마찬가지인 셈이다....? 음.. 모르겠다. 설명을 봐도. 이해를 못하겠다. 일단 패스.  https://leetcode.com/problems/excel-sheet-column-title/discuss/441430/Detailed-Explanation-Here's-why-we-need-n-at-first-of-every-loop-(JavaPythonC%2B%2B)

901. Online Stock Span

이전에 비슷한 접근법을 요구하는 문제가 있었는데, 그 기억대로 접근해서 한번에 해결. 무식하게 매번 전체 array 를 search 할수도 있는데 그러면 Time limt exception 이 뜰거라고 생각했다. 그런데 그렇게 해서도 accept  가 된 솔루션이 있어보이긴 했지만 아무튼. 요지는 두  array 를 관리 하면서, 현재  price 와 span 을 기록하는데, 현재를 기준으로,  현재보다 이전 날짜의 span 은 그 날보다 가격이 같거나 작은날이 며칠인지를 이야기해주고 있으므로, 하루씩 back 할 필요 없이, 이 span 만큼 건너뛰어서 체크를 할수 있다. 물론 index outOfBound 는 피해야 한다. 처음 submit 할때는, 계산하는 함수를 따로 만들어서 뺐었는데, 그랬더니 32ms 가 나왔다. 가장 빠른 성능은 17ms 여서 뭔가 하고 봤는데 내 접근이랑 똑같은데 함수 호출만 없는거였다. 그래서 나도 private 함수로 뺀 부분을 그냥 합쳤더니 17ms 가 나왔다.  보통 이런 함수 호출이 성능에 그만큼 큰 영향을 주나 싶지만, 주어진 조건에 테스트케이스당 최대 만번의  호출을 하고, 전체 테스트케이스 합산시 15만번의 호출까지 한다고 하니. 함수스택 한번 들어갔다 나오는게 늘어나는만큼 유의미한 차이가 있긴 있었나보다. 그래봤자 15ms 가 일반적으로 쉽게 인식 가능한 범위는 아니지만. 아래의 calculateNewSpan 이 문제의 그 추가적인 함수 호출이었다. class StockSpanner { private int [] priceArray ; private int [] spanArray ; private int count ; public StockSpanner () { priceArray = new int [ 10000 ] ; spanArray = new int [ 10000 ] ; count = ...

547. Number of Provinces

한번에 풀지 못했고, intelliJ 를 통해 디버깅을 해야만 했다. 하지만 그렇게 해서라도 해결은 했다.  일단 첫번째 문제는,  정사각형 매트릭스에서 대각선은 전부 1 이기 때문에 대각선의 반쪽만 확인하면 될거라고 생각했는데, 맨 위 row 나 i맨 아래 row 같은 경우는, 맨 왼쪽 혹은 맨 오른쪽에서 시작해야만 자신의 connected node 를 가져올 수 있다.  그래서 0부터  iteration 을 도는데, visited 정보를 따로 관리 하지 않으면 이게 이미 빠진 건지 아닌지를 알 방법이 없다. 그래서 다시 무한루프에 걸렸었다.  visited 를 이용하니 해결. 성능은 좋지 않다.  4ms  였지만, 25% 일단 나의 접근은 set 에 전체 노드를 집어 넣어놓고 꺼내면서, 연관된 node 들을 다 꺼내는 priority queue 를 관리하는 것이었다. 그래서 기존의  set 이 empty 가 되면 종료. 일단 내 접근에서 문제점은, 쓸데없이 PQ 를 썼다는 것이다. 아무이유 없이. 그냥 Queue 를 썼어도 되었었다. 그리고 실제  node 들을 마치 당구공을 주머니에서 꺼내서 다른 주머니에 넣듯이 했는데. HashSet 으로 visit  을 관리할 필요가 전혀 없이, boolean[n] visited 만으로도 충분했다. 그래서 처음부터 각 node 를 Set 에 넣을 필요도, visited 를 set 에 넣을 필요도 없었다. DFS 로도 접근할 수 있는데, 이렇게 접근한 어떤이의 해결법은 다음과 같다. 아래 풀이를 보고 있자면 사실 그렇게 복잡할 필요도 없었겠다는 생각이 든다. public int findCircleNum ( int [][] isConnected) { boolean [] visited = new boolean [isConnected. length ] ; int provinces = 0 ; for ( int i = 0...

Join, FetchMode, FetchType, Fetch Join 에 대해

JPA를 사용할때, 테이블간 join 시 fetch 를 어떻게 하느냐에 따라 DB 에 실제로 hit 하는 query 가 달라지고, 성능에도 영향을 미친다.  아래와 같은,  고객 주문과 (CustomerOrderEntity, customer_orders) 주문history (CustomerOrderHistoryEntryEntity, customer_orders_status_history_entries) 를 담당하는 테이블이 있다고 할때 이런 query가 있다고 하자. @Query( "SELECT t FROM CustomerOrderEntity t JOIN t.orderHistory s WHERE NOT EXISTS (SELECT 1 FROM t.orderHistory intern_s WHERE intern_s.sequenceNumber > s.sequenceNumber) AND ((s.status IN ('DELIVERED', 'CANCELED') AND s.timestamp >= :finishedAfter) OR s.status IN ('CHECKEDOUT', 'DISPATCHED', 'CUSTOMER_NO_ANSWER'))" ) List<CustomerOrderEntity> findAllActiveOrFinishe...

아무도 기다려주지 않는다.

독일에 와서 정말 제대로 느낀게 하나 있다. 금요일 이후에, 스케쥴 표에 우리팀만 이름이 빠져있어서, 채워넣야하지 않냐고 물어봤는데 아무도 답이 없었다. 그러다 다음 월요일에, 다른 사람이 이야기를 다시 꺼내서, 채워넣야 하니 미팅을 하자고 했더니 다들 참여했다.  미팅에서 screenshare 할사람이 없어서 조금 기다리는 공백이 있었는데. 이때라도 나섰어야 했는데 머뭇거렸다. 아무일도 아니었음에도 말이다. 그러곤 빈 slot 에 각자 이름을 넣을 사람을 찾는데 저마다 자기 이름을 넣어달라고 했다. 나는 기회를 기다렸다가 말하려고 했는데. 내가 말할 틈을 주지 않았다. 진짜 모여서, 자기가 되는 시간은 주저없이 자기 이름을 넣어도 된다고 바로바로 말했다. 그렇게 약 5분만에 미팅이 끝났다. 공정한 분배나 이런건 말하지도 않았다.  아무도 기다려주지 않는다. 모두가 서로 돕고 돕는다. 그런데 도와달라고 말을 해야한다. 그러면 언제든 도와준다. 하지만 말을 해야한다. 적극적으로 의사표현을 해야한다. 내가 하겠다고 해야한다. 도움이 필요하다고 해야한다. 뭔지 잘 모르겠다고, 내가 할 수 있다고, 말을 해야한다.  쭈볏쭈볏 머뭇머뭇 하면 기회가 날라가는 것이다. 

자유도 100의 환경에서. 나는 아무것도 할 줄 모른다.

 주입식 교육의 단점이라기엔 스스로 잘하는 사람들이 너무 많다. 소극적인 성격이라기엔 소극적인거랑 일 하는거랑 무슨 상관인가. 양으로 치는거. 이거이거 이렇게 해. 라고 누가 정해주는거. 이런건 밤을 새고, 주말을 써서 한다. 그리고 혼자 뿌듯해한다. 해냈다. 이러면서.  하지만 빈 종이와 연필을 주고. 한번 해봐. 하면 못한다.  뭘 어떻게 해야할지 모르겠다.아무런 생각도 들지 않는다. 리서치를 해야한다고 해도 뭘 어떻게 서칭 해야하는지 감이 안잡힌다. 스펙 던져주고 구현해 라고 하면 마음이 편하다. 이런 방식은 남이 봤을때 비효율적이다. 시간을 많이 투자할줄만 알지, 그 시간 대비 효율성을 따졌을때 가치가 높지 않다. 다른 이유도 있지만, 경력에 비해 경험의 깊이가 별로 깊지 않은 이유이다. 논리적 전개를 해내지 못하면, 다양한 변수가 발생하는 상황에서 일단 문제 해결이 힘들다. 하더라도 효율적인 방안을 제시하지 못한다.  혼자서 생각해내는 힘이 없으면, 평생 남이 던져주는 스펙만 개발하고 살아야 한다. 극히 일부분만 보면서. 그러면 더 높은 곳으로 올라갈 수가 없다. 좋고 나쁘고가 아니라. 연차에 비해 지혜가 없으면 설 자리가 없게 된다.  그러면 시키는대로만 했기 때문에, 경험도 별로 쌓이지 않는다. 회고 할 것도 없고. 가치있는 경험을 했다고 말하기 어렵다.  지금이라도, 늦었더라도, 자유도 100이 주어지면. 나만의 전략을 세워야 한다. 그러기 위해선 목표가 무엇인지를 항상 기억하고. back tracking 이 될수도 있다. 전략을 세우고 싸워봐야. 지더라도 배우는게 있고 발전이 있다. 

peer review feedback 을 받았다.

처음으로 동료들로부터 feedback 을 받았다. 내가 지정한 동료들로부터 받으나, 나에게 돌아오는 결과는 익명이다.  예상했던 대로 self-initiative 는 낮았다. 그러나,quality of work, 나 efficiency  에서도 좋은 점수를 받지 못했다. 평균이란 소리는, 더 잘해야 한다는 소리다. 의외로 team effect 나 knowledge, work commitment 는 좋은 점수를 받았다. 열심히 하고 잘 아는데, 효율적이지 못하고, 스스로 나서지 않으며, 신경써서 일하지 않는다는 결과. 문제를 해결할 때 문제 해결뿐만 아니라, 그 주변의 코드들로 추가적으로 보는 습관들 들여야 한다. 문제를 해결할 때 이 해결된 방안이 다른 부분에 영향을 끼치지는 않는지도 생각해야 한다.  적극적 참여와 의견 개진은, 계속해서 들어오고 있는 피드백이다. 빠르고 바로바로 커뮤니케이션 하라는 주문도 들었다. 말도 못하고 영어는 더 못하는 나를 동료들도 답답해 한것이다.  미안함과 동시에, 답답하기도 했고. 발전의 여지를 인지했고, 발전했음을 나중에 볼 수 있다면 좋겠지만. 참 힘들것이라는것을 알기에. 마음이 좋지만은 않다.

design pattern #13 Behavioral pattern - Command

- 툴박스에 쓸 버튼을 하나 만들었다고 치자. 이 버튼을 상속시켜, 여러가지 저장하기, 복사하기, 붙여넣기 등의 버턴을 만든다고 치자. 뭐가 문젠가? - 문제가 충분히 될 수 있다. 일단, subclass 종류가 너무 많다. 그건 그렇다 치더라도, 복사하기가 버튼에만 있는게 아니고. 메뉴에도 있고, 단축기로도 가능하다. 단축기나 메뉴를 버튼에서 상속하자니 말이 안되고, 그렇지 않으려면 중복된 코드가 생기게 된다.  - command 패턴을 레스토랑에 비교했다. 손님이 테이블에서 주문을 하면, 웨이터는 이를 받아 적어 주방 어딘가에 stick note 를 붙여 놓는다. 요리사는 이 목록대로 음식을 만들어서 다시 내놓고. 웨이터는 목록과 음식을 최종 확인 한 뒤 손님에게 가져다준다. - 비즈니스로직과 GUI 분리의 관점에서, 위 상황의 버튼과 기능을 분리하는게 당연하지만, command 패턴이 말하는건 그냥 분리가 아니다. GUI 가 비즈리스 로직에 request 를 바로 보내는 것이 아니라, 따로 분리된 Command 라는 클래스에, 비즈니스 로직에 필요한 데이터들을 모아두고,  Command 라는 클래스에는 이 요청을 수행하는 method 하나가 존재한다. 그러면 GUI 가 비즈니스 로직에 대해 잘 몰라도, Command 만 트리거 하면 된다.  - Command 클래스는 보통 parameters 가 없는 execute method 하나만 가진다. - 그럼 명령 수행에 필요한 매개변수 같은건 어떻게 넘기는가? 아래 예제를 보면,  Command abstract class 에 생성자로  Editor 를 받는데, Editor 자체로 충분하다. 다른 경우에도, 생성자의 매개변수로 넘기고, execute() 함수에서 각 command 별 자세한 처리를 한다.  - Command  패턴은 이렇듯 객체와 할 행동을 같이 묶어 객체로 넘기는데 사용되고, 객체로 넘기기 때문에 serialize 가 가능하고, rev...

영작 연습을 하다가 간만에 쉐도잉 연습을 해봤다.

원래 올해 목표가 하루 30분씩 쉐도잉 하는거였다가, 하루 20문장 영작 연습하는걸로 바꿔서, 일단 한 20일정도 진행한것 같다.   그리고 주말에 간만에 쉐도잉을 훈련을 다시 해봤다. 다시 하니까 확실히 또 답답하다. 한참 열심히 할때보다 더 느려지고, 버벅이고, 속도를 못따라 가겠다. 이미 반복해서 했던 컨텐츠인데도. 그런데 쉐도잉을 안하다가 간만에 몇번 해보다 보니, 이게 이런 훈련이구나 라는게 느껴졌다. 무슨 말이냐하면.  영어를 말할때의 과정을 굳이 나눠봤다.  1. 머릿속에서 영어로 생각해서 말하기 전까지의 과정 2. 입모양과 목소리를 이용해 영어로 실제로 말을 하는 과정 쉐도잉은 2번을 위한 훈련이라는 결론이 내려졌다. 빠르게 말할때의 입모양, 발음, 억양을 훈련하기에는 쉐도잉이다.영작 훈련은 1번 훈련이다. 실제 상황에서 머릿속에 떠오르는걸 바로 말할 수 있으려면. 한국어로 되어 있는걸 보고 거의 자동으로 영어로 머릿속에 떠올라야 한다.  나는 아직 머릿속에서조차도  느려터졌는데, 입밖으로 내는 훈련이 잘되봐야 무슨 소용인가. 생각해보면 영어로 말할때 매번 느끼는 그 답답함은 1번이지 2번이 아니다. 너무 느려서도 안되겠지만,  2번이 아무리 훈련이 되었더라도 1번에서 보내주지 않으면 소용이 없는 일이다.  내가 회의할때나 이야기할때, 영어 단어를 말할때 사용하는 입모양이 빠르게되지 않아서 더듬거렸던가. 단 한번도 없었다. 머릿속에서 한참 걸린거지. 미리 준비된 대본을 여러번 연습해서 숙지해서 말하는 속도만큼 빠르게 말할 단계는 아직 멀었다.  쉐도잉을 믿고 작년부터 철석같이 믿고 계속 했던 내가 한심스러워지려고 한다. 그러면서 왜이렇게 안늘지 하고 있었다니. 도움이 안되진 않는다. 쉐도잉을 훈련하니 듣기가 느는걸 체감했다.  어쨌든, 다양한 방법으로 시도해보려고 하니 발견하지 못했던걸 알게 되네. 변화가 있다는걸 느꼈다. 계속 해야한다고 생각했던 쉐도잉을...

영작 연습을시작했다.

목표는 하루 25문장이다. 한글을 영어로 영작하고, 정답과 비교하는 연습이다. 약 1시간정도가 걸린다. 그래서 쉐도잉은 주말에만 하는것으로 변경했다. 내 부족한 점 중 하나인 순발력, 속도, 이런것들+ 어쨌든 실전에서의 사용 경험도 중요하기 때문에 회화 수업도 1주일에 1회씩은 되도록이면 계속 진행하려고 한다.  생각해보니 내가 한국어->영어로 바꾸는 영작 연습을 얼마나 해봤던가 싶다. 토익에만 빠져 살다가, 토플 공부한다고, 아이엘츠 공부한다고 학원다니다가. 영국에 잠깐 갔다 왔던 빨로, 오픽이랑 토익을 취업 준비 점수에 맞춰놓고. 이후 전화 영어, 원어민 1대1 회화, 아이엘츠 단과 등을 다니긴 했지만. 영작만 이렇게 하루 1시간씩 훈련을 해본적이 있었나.  회화 실력을 늘리고 싶어 전화영어, 화상영어, 1대1영어 등을 했는데. 아주 미세한 발전은 조금씩 있었겠지만 매번 내가 느끼는건 좌절과 답답함이었다. 그때 필요한게 영작 훈련이었을텐데. 토익 LC 에 나온 것들이라도 잡고 할껄. 무작정 원어민이랑 말하는 기회를 늘리는게 답인줄 알았었다. 나도 모르게, 영어 학원의 현란한 광고들을 보고 혹 했겠지. 그러다 속도가 문제인줄 알고 쉐도잉을 훈련하기 시작했는데. 사실 속도도 속도지만 진짜 원인은 영작 자체가 매우 어렵고 느렸던것이다.진짜 원인은 모른채 쉐도잉만 했네. 그때도 영작에 대해 생각을 안해본건 아니었다. 하지만 그때는, 영작 하면 꼭 어딘가에 글을 써야하는 작문처럼 느껴졌고, 똑같은 말을 한번 이상 하는 경우가 얼마 될까 하여, 모든 경우에 대해 1대1로 영작을 하는게 비효율적이라고 생각했고, 어느세월에 그걸 다 하나 싶었다. 맞는지 틀린지 확인해주는 사람도 없었고. 그런데 지금 돌아보니 그때 그 생각이 틀렸다. 모든 경우에 대해 1대1로 하는게 비효율이라고 해버리면, 나는 한마디도 할수 없다. 그때부터라도, 첫번째 문장부터 하나씩 다 겪어봤어야 그게 쌓였을것이였다. 그때는 말하기 뿐만 아니라 듣기도 문제였으니까 여기까지 신경 쓸...

Spring @Transactional propagation 정리

 Spring 에서는 총 일곱가지의propagation 옵션을 제공한다. @Transactional  로 묶인 함수나 클래스에서 excpetion 이 발생하면 rollback이 된다. 하지만 스프링에서 제공하는 noRollbackFor, noRollbackForClassName, rollbackFor, rollbackForClassName 같은 옵션을 통해 이 역시 설정 할 수 있다. 1.REQUIRED 물리적 transaction 이 없으면 만든다. 이미 존재하면 그 transaction 에 참여한다. 그리고 각각의 @Transactional REQUIRED 로 설정된 메소드 들은 논리적 transaction 을 갖는데, 각각 경계를 가지고 있고, 저마다 범위가 있다.  모든 transaction 이 하나의 물리적 transaction  에 매핑되기 때문에 그중 하나라도 논리적 transaction 이 실패하게 되면 rollback  모든 그 물리적 transaction 에 있는 논리적 transaction 들이 rollback 된다. 바깥에서 catch 해서 처리 한다 하더라도 여전히 transaction 은 rollback 된다. 이미 실패된 논리적 transaction 에서 rollback-only marker 라는것을 세팅 해버리기 때문이다. 이렇게 되면 같은 물리적 transaction 에 있는 것들은 rollback 될수밖에 없다. 2.REQUIRES_NEW 이는 이름에서처럼, 스프링이 항상 새로운 물리적 transaction 을 만들도록 한다. 그렇기 때문에 바깥의 물리적 transaction 의 속성(timeout, isolation level, readonly)을 상속받지 않는다.  각각의 물리적 transaction 은 각각의 database connection 을 필요로 한다는것을 염두해야 한다. 예를 들어 메소드 A 가 메소드 B 를 호출했는데, B 가 REQUIRES_NEW 로 열렸다...

독일 치과 경험기

 치과 검색은 아래의 사이트를 이용했다. https://www.jameda.de/ post code 와 진료 과목을 입력하면 해당 위치의 병원 리스트와 평점 등이 나온다. 공보험,사보험 으로 조건을 걸 수도 있고, 온라인 예약이 가능한지도 필터링 할 수 있다. 언어 설정도 할 수 있는데 정확하지는 않는것 같다. 내가 가보려고 했던 치과는 온라인 예약이 안되어서 홈페이지에 들어가서 메일을 보냈다.  다음날 전화가 왔는데 독일어로 이야기해서 이해를 못하고 서로  sorry 하면서 끊었는데 그 다음날 다시 전화가 왔고 이번에는 치과의사님이 직접 전화를 주셨는데 자기가 영어로 할 수 있다며 예약을 잡아주셨다. 예약당일에 맞춰가서, 보험카드를 체크하고, 사전 문진표를 작성했다. 이건 똑같은듯. 기다리니 선생님님이 들어오신다. 한번 체크를 하고, 엑스레이를 찍은 뒤, 이것저것 체크를 하고 진료를 받았다. 영어로 해줘서 큰 어려움은 없었는데, 치석제거를 치위생사님이 해주셨는데 혼자 하다가 어려웠는디 다른 동료분까지 와서 같이 해주셨다. 임플란트에 관련된건 보험이 적용되지 않는다고 한다. 나는 실밥 제거만 한 것 뿐인데 31유로가 나왔다. 본인이 그정도 나올거라고 이야기 해줬는데 정말 그대로 나왔다며 치과의사님이 재밌어하셨다. 한국에서는 이정도는 그냥 해줬을텐데. 크라운 같은건 하나에 거의 400유로가 든다고 하는데. 보험을 제외하더라도. 한국이랑 비교해보고 하겠다고 했다. 무슨 종이를 줬는데, 이걸 보험사에 보내면, 보험사에서 자기네들이 얼마를 지불해줄건지를 알려준다고 한다. 그 다음에 하고싶으면 다시 연락해서 예약을 잡으라고 했다. 감사하다고 하며 나왔다. 기기나 이런건 역시 한국이 짱이다. 한국은 기다리는동안 화면에 예능을 틀어주고, 모니터에 바로바로 엑스레이 띄워주는데 . 여기는 그런건 없었다. 아이패드로  엑스레이를 보여주긴 했다. 하지만 처음부터 끝까지 의사님이 직접 설명해주셨다. 듣던대로. 그리고 진료할때 눕게 되는 진료대가 각...

나에게 맞는 영어 공부 방법은 뭘까

영미권에 태어나지 않은, 어렸을때 살다온것도 아닌. 토종 한국인의 영어 공부 과도기. 지금 내 수준에 나에게 맞는 공부법은 뭘까. 어떻게 해야 효율적으로, 시간 낭비를 최소화 할까. 초급은 쉽다. 채워야할 지식도 많고. 단어, 문장구조, 기본 회화표현들. 고급은 단순하다. 이미 일정 수준에 올라섰으니, 쉐도잉을 하면서 계속 쌓아가면 된다.  중급은 모르겠다. 어디까지가 중급인지도 모르겠다. 그리고 중급에서 고급으로 가기 위해 뭘 해야하는지도. 

영어 스피킹 쉐도잉 되돌아보기

몇가지 기억나는 사실들이 있다. 스카이프 화상 영어를 하던 중에, 왜 영국영어를, 혹은 미국영어를 따라하려고 하느냐? 였다. 억양과 액센트를 이야기 하던 도중이었는데. 따라하려고 노력하고 있다니까 왜? 라는 질문이 돌아왔다.   이때는 이렇게 생각했다. 아 꼭 원어민처럼 할 필요는 없구나. 생각해보면 영어에 유창한 중국인이나 특히나 더 많은 경우의 수가 존재하는, 영어에 유창한 인도인들의 영어를 보면. 매우 유창하고,  fluent 해서 원어민과 아무런 문제 없이 의사소통 하고 논쟁을 하는데. 내 입장에서 보면 이상한 영어처럼 들린다. 흔히 생각하는 영어권 국가의 네이티브 영어가 아니기 때문이다. 하지만 그들은 의사소통 하는데 아무런 불편이 없어 보인다. 그래서 꼭 원어민처럼 따라할 필요는 없구나. 자연스럽게 말하는게 가능하고 의사소통에 불편함이 없음을 상호간에 인지한다면, 아니 인지할 문제조차 되지 않는게 베스트겠지만, 어쨌든 굳이 영국영어를, 미국영어를 따라가지 않아도 되겠구나 라고. 그리고 또 언젠가 한번은 그냥 틀어놓은 모던패밀리를 보면서, 쉐도잉을 하려고 보진 않았지만 그냥 말이 빠르고 어조가 재미있길래 쉐도잉을 한번 해볼까 해봤는데, Haley 의 말을, 몇번을 반복해서 자막을 보면서 해도, 결코 따라 할 수가 없었다. 복잡하고 어려운 단어도 아닌데. 열받아서 화내고 빡쳐하는 장면을 아무리 반복해도 따라갈 수 없었다. 속도도, 발음도, 억양도 모두.   그때 생각했다.. 다시 태어나지 않는 이상 내가 원어민처럼 말하는건 불가능하다고 생각했다. 초등학생일때 몇년씩 살다 오지 않는 이상, 성인이 되어 시작하는 영어는 원어민처럼 되는건 아예 불가눙하구나 라고. 그러면서도 달리 방법은 없고, 꾸준히 하는 수 밖에 없다고 생각했다.  그러다 오늘 어떤 유튜버의 채널이 추천에 떠서 봤는데. 토종 성인 한국인이 영어를 시작해서 어디까지 스피킹을 할수 있는가. 결론은 원어민처럼은 절대 안된다. 를 확인사살 시켜주...

763. Partition Labels

풀지 못했다. 가장 많은빈도수에 오른 문제임에도 불구하고. 처음 풀어보는 문제였는데. 못풀었다.  그동안 풀었던 문제는 사실 한번씩 풀어봤던 문제들이다. 그래서 쉬웠고, 그래서 한번에 통과도 하고 그랬던 것이다. 처음보는 문제는 또 이렇게 당황하고, 접근을 못한다. 각 알파벳의 처음과 마지막 index 를 찾아서, (a,b) 이런식으로 만들고,  겹치는 알파벳들은 merge  하면 될것 같았다. 하지만 그렇게 하면 merge  를 하더라도 문제에서 말하는 답을 return 하기엔 또 정렬을 하고, 계산을 해야한다. 생각해보니, 어떤 인도인에게 이 질문을 받은것 같기도 하다.그때. I said "infinite" 이라면서. infinite pool 에 알파벳들이 있는데. 하나씩 꺼낼수 있고, 이럴때 한번만 나타나도록 partition 을 구하라고 했었다.  그때도 못풀었고, 지금 역시,  infinite  가 아닌데도, 못풀었다. 비슷한 문제인지 조차도 한참 뒤에 알았다. 그때 당시엔 새로운 문제인줄 알았는데. 새로운 문제가 아니었다. 수많은 문제 은행 속 문제중에 내가 아직 안풀었던 것 뿐. 이미 2018년도에 누군가들이 풀었던 문제들이었던 거다. 나는 몰랐다가, 2019년 6월에 처음 그 문제를 인도인한테 접했고. 끝내 풀지 못한 내 풀이는 장황하고,  두서없고, 결론을 맺지 못했다. 그러나 역시 정답은 생각보다 간결하고 깔끔했다. 늘 그렇다. 각각의 알파벳 캐릭터의 가장 마지막 index 를 배열 26개에 관리한다.  그리고 for 를 toCharArray() 에 대해 돌면서 각 index 별로 그 캐릭터의 last index 를 가져와 last  라는 변수에 저장한다.  그리고 이렇게 유지한  last 와 현재 캐릭터의 last index 중 max 값을 last 에 계속 유지한다.  그래서, 현재 index  가 last ...

733. Flood Fill

dfs 접근 법을 사용했고, number of islands 와 유사하나, 시작점의 색깔과 동일한 색깔만 바꾼다는 조건이 추가되어 있긴 하다. 오타, 대소문자를 꼼꼼히 살필것. int 를 init 으로 쓴다거나,  newColor 를 newcolor 로 써서 compile error  가 났다. 이를 제외하고는 한번에 accept. matrix 가 MxN  이라고 하면,  최악의 경우 모든 배열을 바꿔야하므로,  시간 복잡도는 O(MN)  이 된다.  간단한 문제여서 더 쓸건 없지만, 만약 BFS 로 접근해야 한다면 어떻게 해야할까?  자주 했었는데,  Queue 를 쓰면 된다. java 에서 Queue 구현은 LinkedList 로 되어 있다.  따라서 맨처음 주어진 포인트를 Queue 에 넣고, 뽑아서 체크하고, 4방향의 포인트들을 다시 queue 에 넣고. 이런식으로 해서 queue  가 텅 빌때까지 돌면 된다.  이 경우 queue 에 넣을 때 4방향 포인트를 다 넣을 필요 없이, 주어진 조건에 부합해서 색을 변경한 경우에만 넣으면 된다. 

design pattern #12 Behavioral pattern - Chain of Responsibility

Chain of Responsibility 는 여러 가지의 기능을 개별 class 에서 구현하고, 이를 연결, 연결, 연결 해서,  client 에서 필요한 chain  을 연결해서 쓸 수 있게 한다.  netty 에서 여러가지 request handler 를 연결해서 쓰는것이 바로 이 패턴이다. 모든 class 는 당연히 동일한 interface 를 구현하고, next chain 으로 넘길지, 바로 처리할지를 구분 할 수 있다. runtime 동적으로 필요한 체인을 원하는 순서대로 연결해서 쓸 수 있고, 잘 쪼개지면 좋은 설계가 된다. 아래 예제는 Middleware 라는  abstract class  안에, Middleware next 라는, 다음 handler 를 담기 위한 변수가 있고,  abstract boolean check() 라는 method 가 각각 구현체에서 구현할 함수이다. linkWith 라는 생성자처럼 생긴 public 함수는, next handler 를 받고 그걸 돌려준다.  abstract check 를 구현하므로, 각각의 handler 는 동일한 parameter 를 받는다. checkNext 함수는 각각의 구현된 check 함수에서 쓰이며, 다음 handler 로 넘길지, 끝낼지를 결정할 수 있다. public abstract class Middleware { private Middleware next ; public Middleware linkWith(Middleware next) { this . next = next; return next; } public abstract boolean check(String email, String password); /** * Runs check on the next object in chain or ends traversing if we're in ...

design pattern #11 Structural pattern - Proxy

API Gateway  느낌의 proxy 가 아니고, 말 그대로 객체(database 연결)  등을 대리하는 proxy pattern 이다. database connection 같은 경우, 무거운 resource 인데, 필요할때 쓰는 lazy initialization 이 좋은데, 이렇게 하면 connection 을 만들어 쓰는 곳마다 lazy initialization 을 해야한다. original service object 와 동일한 proxy 를 만들어, 우리에게 필요한 추가 작업을 해서 필요한 경우에만 실제 object 를 실행하도록 할 수 있다. lazy initialize, 결과를 caching 해두고 쓰거나, access control 을 할 수 있다는 장점이 있다. 클래스 구조가 복잡해지거나,  한번 거쳐가기 때문에 응답에 delay 가 생긴다는 단점이 있다. 코드를 3rd-party  라 바꿀수는 없는데, 추가 기능은 추가해야하는 경우 유용하다. youtube downloader 예제로 보면, 일단 ThirdPartYoutubeLib 가 interface 로 있고, ThirdPartyYoutubeClass 가 이를 구현한다. YoutubeCacheProxy 도 ThirdPartyYoutubeLib 를 구현하는데, ThirdPartyYoutubeLib 를 필드로 갖는다. cache 체크등을 하여 이미 있는 비디오는 cache 에서 리턴하는 등의 예제를 보여준다. 일단 design pattern 을 보면, 모든것은 interface 로부터 시작하는것 같다. 그리고 그를 implement 하고, interface 를 field 로 갖고, 혹은, method 의  return type 이 interface 라거나.  등등이다.  public interface ThirdPartyYouTubeLib { HashMap<String, Video> popularVideos(...