Posts

Showing posts with the label develop

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

성장을 해야한다. 시간이 지날수록, 경력 기간이 늘어날수록, 실력도 증가해야 한다. 단순히 시간이 지난다고 해서 실력도 발전하진 않는다. 여태까지 그랬다. 시간을 어마어마하게 쏟아부으면, 당연히 없던 실력에선 어느정도 발전이 있을수밖에 없지만. 어느새부턴가 단순반복이 되어버리면, 배움도 없고 발전하지 못한다.   회고의 중요성 실력이 증가하려면 시간과 경험이 일단 쌓여야하지만, 무언가 일단락 되었을때 되돌아봐야만 한다. 늘 언제나 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 을 쓰도록 해야겠다.

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...

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

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

peer review feedback 을 받았다.

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

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 로 열렸다...

Postgres SELECT WHERE 에서 EXIST / NOT EXIST 에 대해

EXIST 의 parameter 로  임의의  select 구문이나 subquery  를 받는다 판단은, param 의 결과가 최소 1개 이상의 row 를 return 하면 TRUE, 아니면 FALSE 이다 최소 하나라도 return 하는지가 중요하므로, 실제  return  결과는 관심이 없다 그래서 판별식 내부는 주로 select 1 이 쓰인다 far enough to determine 이라서,  statement 를 끝까지 완료하지 않을 수 있다(1개 발견되면 끝) NOT EXIST 는 반대로 판별식을 만족하는 row  가 하나도 없을때 TRUE 를 return 한다 *EXIST 한번이라도 100 보다 큰 amount 를 지불한 적 있는 고객 SELECT name FROM customer c WHERE EXISTS ( SELECT 1 FROM payment p WHERE p.customer_id = c.customer_id AND amount > 100 ) ORDER BY name; *NOT EXIST 한번도 100 보다 큰 amount 를 지불한 적 어는 고객 SELECT name FROM customer c WHERE NOT EXISTS ( SELECT 1 FROM payment p WHERE p.customer_id = c.customer_id AND amount > 100 ) ORDER BY name;

refactoring #6 Dealing with Generalization

subclass 들에 중복되고 거의 유사한 field, method 는 부모 class 로  끌어올린다 부모 class에 있으나 하나의 subclass 에서만 사용된다면, 그쪽으로 내린다 한 class 에 있으나 일부만 따로 떼어질거 같으면 subclass 를 만들고 그쪽으로 다 옮긴다 서로 다른 class 에 비슷한 method 나 비슷한 부분이 있으면 superclass 를 만들고 상속받는다 subclass 가 시간이 지나며 superclass와 거의 똑같아졌다면, 합한다. 대신 다른 subclass 는 없는지, 합쳤을때 문제는 없는지 고려해야한다 시간이 지나면서, subclass 들 사이에 비슷한, 정렬 같은 알고리즘이 거의 비슷하게 존재하게 될 수가 있는데. template 형태로 superclass 로 옮길수 있다면 옮긴다. 경우에 따라 delegation 을 inheritance 로, inheritance 를 delegation 으로 바꿀 수 있다.

refactoring #5 Simplifying Method Calls

아래 내용들은 바꿀 경우, super/sub class 에도 해당 되는지도 체크 해야한다 method  이름은 간결하되, 내용을 제대로 표현하게.  method  에  parameter 추가는 좋으나, parameter 는 늘 추가하는건 쉽고, 삭제하는건 어려우며, 대개 param 사이즈가 엄청 늘어나게 되며 이경우 다른 refactoring 이 필요하다 사용되지 않는 parameter 는 삭제한다   조회하는  query 와 수정을 가하는 modifier 는 따로 다른 method   로 분리되어야 한다.  비슷한 method 인데 parameter 만 다른 경우, 하나로 합치고 parameter 로 분기할수 있는데, 자칫하다간 매우 길고 복잡한 하나의 method 로 합쳐질 수 있어 이 경우는 지양해야한다 위와 반대로, 하나의 method  가 길고 복잡하고 불필요하게 parameter 가 많은 경우, 두개의 method  로 나누고, parameter 도 필요에 따라 쪼갠다. parameter 여러개가 한 object 에서 나올 경우, object 를 그냥 넘겨도 된다. 하지만 int, String 같은 거였다가 object 로 바꿀 경우그럴 경우, 그 object 만이 method 에 쓰일 수 있다.  method 안에서 해결 될 수 있는 계산이면, method 안에서 처리 한다. 밖에서 해서 parameter 로 넘길 필요 없이 parameter  들이 많고, 자주 method 에서 쓰이면 parameter object 로 하나의 class 로 묶고, 관련된 method 들도 거기로 옮겨버리면 깔끔해질 수 있다 생성자에서 변수 할당 이외에 복잡한 작업을 할 경우, factory method  로 대체한다. -1  같은 에러코드를 리턴하는 대신 exception 을 던진다.  0, -1 같은 코드가 아니므...

refactoring #4 simplifying conditional express

if 구문 안이 장황해지면 읽기 힘들다.  가능하면 extract 한다 nested if 를 and 로 묶거나,  동일한 결과를 return 하는 if를 or 로 묶어서 extract한다 if 와 else 모두에 중복된 코드가 있으면 if-else 밖으로 뺀다.  nested hell은 피한다. exception, 바로 return 하는 것들을 최대한 빼고 평평하게 만든다 switch-case 가 길어지고 복잡해지면, 각각의 case 를 abstract- subclass 로 뺄 수 있는지 본다. 이 경우 새로 추가되는 case 가 있다 해도 기존  class 수정 없이 subclass만 신규 추가된다는 부가적인 장점도 있다. 메소드 실행시 Assert.isTrue 로 분명히 할건 assert  걸어둔다. 꼭 JUnit  에서만 쓰이는게 아니다. assertion 을 확실히 해두면 live documentation 이 된다. 물론  overdo 해선 안된다. introduce Null object 는 처음 본다.  예를들어 if(customer==null) 같은 체크가 많으니, NullCustomer 라는  class 를 Customer class  에서 상속받아 만들어서 null check 를 더 간결하게 하는 것이다. 더 복잡하게 하는거 같은데. 어쨌든 이런 방법도 있다니.

refactoring #3 organizing Data

 1. getter, setter의 사용. 당연하다고 생각했지만, subclass 에서 getter, setter 를 redefine 할 수 있다는 장점. setter  를 아예 없앰으로써, construct 할때 설정된 값이 항상 사용되는 final  효과를 줄 수있다는 점은 처음 알았다. 2. business logic  dto  와 GUI 에 사용되는  dto 는 반드시 분리해야한다. 그렇지않으면 골치아파진다. 그럼 buisness 를 여러명이 같이 개발 할 수도, 여러 GUI 에 대한 dto 를 각각 개발할 수도 없어진다. gui  관련된 dto 는 만들어본적이 없었는데. 얼마전 경험을 하다가 겪었다. 반드시 분리해야한다. 혼자 하는데도 불구하고 여려번 수정해야 하는 노가다가 있었다. 여러명이 작업한다면 불가능했을것이다.  3. encapsulation 이 java  의 기본이긴 하지만. Point  라는 java 클래스의  x, y 변수는 public 이라고 한다. 성능상의 큰 영향이 있는 이런 특수한 경우에는 getter/setter 대신 public 접근을 할 수도 있다. 하긴 지금 회사도 초반에 그런 것들이 꽤 있었다. 악영향을 끼치지 않고, readable  하고, 성능적인 이득을 얻는 경우. 4. collection 의 경우, encapsulation 의 형태가 좀더 달라야한다. getter/setter 라고는 하지만,  collection 자체를 getter  로 내어주는 경우, readonly  가 되어야 하며, setter 대신 각각의 item 에 대해 add, remove item 하는 함수를 만들고. setter 자체는 collection replace 가 되기 때문에 이에 유의해야 할 필요가 있다.  change value to ref change ref to value change bidir...

refactoring #2 moving features between Objects

이번 장은 주로 여기저기 퍼져있는 method들을 다시 재배치하고, public 에서 가릴건 가리고, 하는 방법이다. 1. method 나 class  를 따로 빼거나 이동하게 되면, 작업을 마친 뒤 original method, class  를 다시한번 살펴본다. 그러면 single-responsibility 를 더 잘 표현하는 increased clarity 로 renaming 할 수 있을지도 모른다. (여러 기능을 하던 것들이 빠져나갔기 때문에) 2. 이런 경험이 많지는 않아도 한 두번 있었던것 같은데.  library  class 에 원하는 method 하나가 없는 경우가 있다. 그런 경우, 아래와 같은 방법이 가능하다.  introduce foreign method method  를 하나 만들어서,  거기에 library object  를 parameter 로 받아서 필요한 기능을 구현한다.  introduce local extension    library class 를 extend 하거나, wrapper class 를 만든다. final  keyword  등으로 extend 를 할 수 없는 경우 wrapper class 를 만들어서 감싸면 되는데, 이 경우 기존 library class 의 모든 public class 를 delegate 해서 호출해줘야 한다.: 전반적으로 이번챕터는 지난  extract 챕터와 거의 유사해보인다. 아직 이런 경우에 대한 경험이 없어서 그런것 같다. 어쨌든 요점은, 1 class  1 responsibility 를 유지하는 것이 중요하며, class 가 점점 커져가면서 여러가지 field, method  들이 추가되게 되면, 어느 순간 extract class 하는것이 필요하고, 이때 관련 field, method 들을 새로 만든 class 로 이동시키면된다. 그리고 ...

Efficient PostgreSQL Index 생성을 위한 몇가지 참고점

B-Tree MySQL 과 마찬가지로, CREATE INDEX 를 하게 되면 B-Tree 를 사용한다.  B-Tree 는 별도로 공부해야하지만,  it tries to remain balanced. 가 핵심이다. 각 tree의 branch 들에 속한 값의 양들이 거의 동일하게된다.  INDEX  Case by case  select * from foo where bar = 1 select * from foo where bar = 2 bar=2 인 경우가 굉장히 많으면, 오히려 안타게 된다. sequential scan 이 index scan 보다 훨씬 빠르기 때문이다. Partial Index Index 는 Index 인데, where 조건이 포함된 Index 이다 Index size 를 줄임으로써 Index에 대한 효율성을 높일 수 있다 아래와 같은 경우, comments 중 flag 가 true 인 것들에 대해서만 created_at에 Index 를 걸 수 있다.  CREATE INDEX idx_comments_flagged_created_at ON comments ( created_at ) WHERE flag IS TRUE ; Expression Index data 를 function 에 넣은 결과값에 대해 Index를 걸 수 있다.   예를들어, 사용자의 email 계정을 저장하는  column  이 있다고 할때,  사용자가 입력한대로 값은 저장하되 로그인등 인증시에는 아래처럼 소문자로 처리하고 싶으면,   WHERE lower(account) = '{lowercased_email}'  Index 는 아래와 같이 걸수 있다.  CREATE INDEX idx_users_account_email ON users ( lower ( account ) ) ;   혹은 Timestamp Column 에 대해 날짜에 대...

OptaPlanner 공부하기 - 1

Optaplanner 란 간단히 말해서, 최적화 문제를 인공지능적인 방법으로 접근해서 해결해주는 open source java library 이다. maven 을 통해 import  를 할 수있으며, 소스 또한 github 에 공개 되어 있다. pure 100%  java 로 짜여있고, SpringBoot 와도 compatible 하다.  문제를 해결하기 위한 수학적 방정식같은걸 짜지 않아도 된다고 한다.  Optaplanner 라는 이름에서도 유추할 수 있겠지만, 이 도구가 해결해주는 문제는 간단히는 knapsack problem 부터 시작 해서,  vehicle routing, employee rostering, maintanence scheduling, task assignment, school timetabling 같은 것들이 있다. 제한된 자원을 문제 해결을 위해 할당해서 처리해야 하는데 optimal solution  을  내주는 것이다.  인공지능 하면, 방대한 데이터를 학습시켜서 판단하는 gene 같은걸 형성하는 거라고 생각했는데, maven library 를 import 하는 것만으로도 된다니 신기하다.  knapsack 문제 해결하는 예제를 따라가면서 해봤는데, 일단은 신기하다. 일단 개발자가 해야하는 일은 문제와 제약조건들에 annotation  을 달면 된다.  하나하나 앞으로 공부해가야 할 것들이다. @PlanningEntity, @PlanningVariable, @PlanningEntityCollectionProperty, @ProblemFactProperty, @PlanningScore solution 에 제약 조건들은 예를 들면 아래처럼 나타낼 수 있다. knapsack 같은 경우, maxWeight 를 넘으면 안되면서(penalize),   private Constraint maxWeight(ConstraintF...

MySQL slow log 원인 찾기 / "commit; set timestamp" analysis using performance_schema table

Image
MySQL slow query 를 보다보면 이해가 가지 않는 경우가 있다. # Time: 2020-07-02T15:44:14.145642Z # User@Host: mydatabase[mydatabase] @ [10.1.1.5] Id: 32026 # Query_time: 0.200300 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0 use mydatabase; SET timestamp=1575301453; commit; 위 로그는 실제로 겪은 경우인데, Lock_time 도 0이고, rows_sent, rows_examined 도 0인데 0.2초가 넘는 시간이 걸렸다. 한번이면 그냥 무시하고 넘어가려고 했는데, 이 로그가 수십번 넘게 계속 쌓여가고 있어서 찾아봤다. MySQL 에서 제공하는 테이블중 innodb_trx 라는 테이블이있다.   select * from information_schema.innodb_trx; 실행 해보면 위와 비슷한 결과가 나오는데, application server 로부터 DB 에 connection 을 맺고 현재 진행중인 transaction 을 볼 수 있다. 왠만한 쿼리가 아닌 이상 매우 짧은 시간안에 끝나기 때문에 수행 할 때마다 결과 값이 바뀐다. 하지만 더 재미있는 테이블은 performance_shcema DB에 있다. MySQL 8.0부터 제공했던것 같다. https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html 여러가지 테이블이있지만 그중 가장 관심이 있는 테이블은 events_statements_history 와 threads 테이블이다. 이제 위 테이블의 trx_mysql_thread_id 컬럼의 값을 이용해서 performance_schema 를 조회해볼 수 있다. 그럼 저 trx_mysql_thread_id 에서 어떤 일들이 일어났는지를 알 수 있다. select SQL_TEXT FROM perform...

IDENTITY_INSERT가 OFF로 설정되면 테이블 'products'의 ID 열에 명시적 값을 삽입할 수 없습니다.

Springframework JPA 를 사용해왔는데,  PostgreSQL, MySQL 에선 본적이 없던 에러가 나왔다. 테이블 ID 컬럼 속성에 auto increment 옵션을 달아놨는데 JPA에서 create 를 할때 id   값을 지정하려고 하니 이런 에러가 발생했다.  영어로는 Cannot insert explicit value for identity column in table 'products' when IDENTITY_INSERT is set to OFF 이런 식이다. 그냥 이 에러로 검색하면 해결법이 테이블 속성을 바꾸거나, 아래와 같이 쿼리를 수행 할 때 이전과 이 후에 처리를 해주는 것으로 나왔다. SET IDENTITY_INSERT (table) ON INSERT  SET IDENTITY_INSERT (table) OFF 하지만 JPA 를 사용할때는 이런 쿼리를 수행하기가 까다로워서 더 찾아봤다. 해결 방법은 간단했는데, @GeneratedValue (strategy=GenerationType. IDENTITY ) 를 Entity 클래스의 column  선언에 추가해 주면 된다.  public class ProductEntity { @Id @GeneratedValue (strategy=GenerationType. IDENTITY ) @Column (name = "id" , nullable = false ) public int id ; } 이런 식으로 수정을 해주고 나니 에러 없이 데이터 추가가 잘 되었다.  

refactoring #1 composing method

composing method  refactoring 의 제일 기본. 코드가 길면 이해하기 어려워지고, 이해하기 어려우면 변경하기도 어렵다. 변경하기 어려워지면 방치될 수 있고, 잠재적인 결함의 원인이 되거나, 비즈니스 로직의 변경에 대처하는 비용이 증가하게 된다.  독일에 와서 일하기 시작하면서,  code review 엄격하게 하는 환경이 되었는데. 가장 먼저 내가 받았던 review 들은 너무 길어서 이해하기 힘들다는 것이다. 별로 안길다고 생각했는데, 다시 생각해보니 "모르는 사람, 혹은 처음보는 사람 입장에서 코드를 봤을 때 이해하기 쉬운지" 의 관점에서 생각해본적은 한번도 없는 것 같다. 여러차례 review 에서 지적을 받은 끝에, 지금은  commit 할 때마다 길이를 다시한번 확인하는 습관이 생겼다. 제일 기본적인 내용이지만 생각해봐야 할 점들이 있다. 1. refactoring 혹은 review 를 하다보면 주석으로 적혀있는 것이 그대로 함수명이나 변수명이 되는 경우, 혹은 assert 의 문구가 되는 경우가 있다. 그런 경우 함수명이나 변수명이 그 뜻을 제대로 내포하지 못했다는 뜻이거나, 주석이 더 잘 표시했다는 경우이다.  우리회사에서의 주석의 정체는, what 보다는 why 에 대해 남기자는 정책인데,  why 에 대한 입장에서 naming 하는것이 더 깔끔한 경우가 있는것 같다. Exception 을 던지는 경우에도, Exception 옆에 주석을 다는 것보다, Assert(condition, "comment"); 로 표시하는 것이 더 깔끔해보였다. 2. 쪼개는 것의 단점 if(a() || b()) 의 경우,  a() 가 true 이면 b 는 실행하지 않는다. 어차피 true 이기때문이다. 하지만 이걸 extract 해서 위로 빼면  aa= a() bb = b() if (aa || bb) 같은 식이 되므로, 이때는 항상 a(), b() 를 모두 실행한다. 따라서 re...

optimistic lock vs pessimistic lock

optimistic lock : 말 그대로 lock을하고 update 를 하는 것에 대해 낙관적이다. 일단, 각 table 별로 추가적인 column 을 사용한다. hash, timestamp, version  등이다. 실패하지 않을것이라고 생각하고, lock 없이 update  를 시도한다. 대신, 읽었을때와 쓰는 순간에 version 을 비교해서 같으면 그사이 변경이 없었다는 뜻이므로 update 를 마무리를 하고, version값을 1 증가시킨다. 만일 비교한 값이 다르면 그사이에 이미 update 가 되었기 때문에 현재의 transaction  결과물은 무의미해진다. 따라서 이 결과는 쓰일수가 없고,  application level  에서 재시도를 할지, 무시할지 등에 대해 처리를 해야한다. pessimistic lock : update 를 하는것에 대해 비관적이다. 그러므로 update 를 하기 전 해당  row 에 대해 lock 을 걸어잠그고  update 를 한다. 그렇기 때문에 일단 lock 을 얻었으면 별다른 이유가 없는한 현재 transacton은 실패하지 않고 DB 에 쓰이게 된다. 다만, 그사이에 다른 transaction 에서 접근하는데 제약이 있다.  제약은 다시 두종류로 나누게 된다.  shared / read lock : read  는 하게 해준다 exclusive / write lock : read 도 못하게 한다 성능 측면에서 보면, pessmistic lock 이 무조건 걸어잠그고 들어가기 때문에 optimistic lock 이 더 유리하다고 볼 수는 있다. pessmistic lock 은 더구나 deadlock  의 잠재적인 위험성도 가지고 있다. concurrent access 에 따른 conflict 가 적을 것으로 예상되면, optimistic lock 을 써도 된다고 볼수 있겠다. 하지만 conflict 가 매우 많이 발...

SwiftUI @State, @ObservedObject, @EnvironmentObject 익히기

 앱을 개발하려고 보면, 사용자의 입력을 받든, 서버에서 값을 가져오든, 변수에 값을 저장하고, 그 값의 변화에 따라 화면의 UI 가 바뀐다. objective-c와 이전의 swift 에서는 어떻게 했는지 까먹었으나, SwiftUI 는 새로 공부해보면서 정리하려고한다. There are several concepts regarding the binding between data and view of the data in SwiftUI. Below is what I understood from other developer's blogs. @State The most basic annotation that we can use. The important thing is it can be only used in a specific view.  So usually I'd use with `private` keyword. With @State basically,  struct View 밖의 special memory 에 저장되고, it is managed by SwiftUI. 이 값이 바뀔 때마다 SwiftUI 는 해당 view 를  rebuild 한다. @ State private var showFavorited : Bool = false var body : some View {      VStack{          Button(              action: { self .showFavorited.toggle() },              label: { Text( "Change filter" ) }          ) ...