Jini's Blog

Ing...

  • Home
  • Business
    • Internet
    • Market
    • Stock
  • Parent Category
    • Child Category 1
      • Sub Child Category 1
      • Sub Child Category 2
      • Sub Child Category 3
    • Child Category 2
    • Child Category 3
    • Child Category 4
  • Featured
  • Health
    • Childcare
    • Doctors
  • Home
  • Business
    • Internet
    • Market
    • Stock
  • Downloads
    • Dvd
    • Games
    • Software
      • Office
  • Parent Category
    • Child Category 1
      • Sub Child Category 1
      • Sub Child Category 2
      • Sub Child Category 3
    • Child Category 2
    • Child Category 3
    • Child Category 4
  • Featured
  • Health
    • Childcare
    • Doctors
  • Uncategorized

오브젝트 : 코드로 이해하는 객체지향 설계

 Jini     오후 11:03     도서요약     No comments   

오브젝트 - 코드로 이해하는 객체지향 설계 / 조영호 지음 / 위키북스

객체지향에 대해 그 동안 잊고 있었던 것들을 상기시켜주고 새로운 인사이트를 줬으며 그 동안의 설계에 대해 돌이켜 보게 해준 유익한 책.

객체 사이의 의존성을 완전히 없애는 것이 정답은 아니다. 최소한의 의존성만 유지하고 불필요한 의존성을 제거하는 것이다.

객체가 어떤 데이터를 가지느냐보다는 객체에 어떤 책임을 할당할 것이냐에 초점을 맞춰야 한다.

객체지향 프로그램을 작성할 때 가장 먼저 고려하는 것은 무엇인가? 대부분의 사람들은 클래스를 결정한 후에 클래스에 어떤 속성과 메서드가 필요한지 고민한다. 안타깝게도 이것은 객체지향의 본질과는 거리가 멀다. 객체지향 패러다임으로의 전환은 다음의 두 가지에 집중해야 한다.
첫째, 어떤 클래스가 필요한지를 고민하기 전에 어떤 객체들이 필요한지 고민하라.
둘째, 객체를 독립적인 존재가 아니라 기능을 구현하기 위해 협력하는 공동체의 일원으로 봐야 한다.

의존성의 양면성
코드의 의존성과 실행 시점의 의존성이 다르면 다를수록 코드를 이해하기 어려워진다는 것이다. 코드를 이해하기 위해서는 코드뿐만 아니라 객체를 생성하고 연결하는 부분을 찾아야 하기 때문이다. 반면 코드의 의존성과 실행 시점의 의존성이 다르면 다를수록 코드는 더 유연해지고 확장 가능해진다.
설계가 유연해질수록 코드를 이해하고 디버깅하기는 점점 더 어려워진다는 사실을 기억하라. 반면 유연성을 억제하면 코드를 이해하고 디버깅하기는 쉬워지지만 재사용성과 확장 가능성은 낮아진다는 사실도 기억하라. 여러분이 훌륭한 객체지향 설계자로 성장하기 위해서는 항상 유연성과 가독성 사이에서 고민해야 한다. 무조건 유연한 설계도, 무조건 읽기 쉬운 코드도 정답이 아니다. 이것이 객체지향 설계가 어려우면서도 매력적인 이유다.

역할,책임,협력
객체지향 패러다임의 관점에서 핵심은 역할(role), 책임(responsibility), 협력(collaboration)이다.

협력
객체지향 시스템은 자율적인 객체들의 공동체다. 객체는 고립된 존재가 아니라 시스템의 기능이라는 더 큰 목표를 달성하기 위해 다른 객체와 협력하는 사회적인 존재다. 협력은 객체지향의 세계에서 기능을 구현할 수 있는 유일한 방법이다. 두 객체 사이의 협력은 하나의 객체가 다른 객체에게 도움을 요청할 때 시작된다. 메시지 전송은 객체 사이의 협력을 위해 사용할 수 있는 유일한 커뮤니케이션 수단이다. 메시지를 수신한 객체는 메서드를 실행해 요청에 응답한다. 여기서 객체가 메시지를 처리할 방법을 스스로 선택한다는 점이 중요하다.
협력이 설계를 위한 문맥을 결정한다. 객체의 행동을 결정하는 것은 객체가 참여하고 있는 협력이다. 협력이 바뀌면 객체가 제공해야 하는 행동 역시 바뀌어야 한다. 협력은 객체가 필요한 이유와 객체가 수행하는 행동의 동기를 제공한다.

책임
객체의 책임은 '무엇을 알고 있는가'와 '무엇을 할 수 있는가'로 구성된다. 크레이그 라만은 이러한 분류 체계에 따라 객체의 책임을 크게 '하는 것(doing)'과 '아는 것(knowing)'의 두 가지 범주로 나누어 세분화하고 있다.
객체는 자신이 맡은 책임을 수행하는 데 필요한 정보를 알고 있을 책임이 있다. 또한 객체는 자신이 할 수 없는 작업을 도와줄 객체를 알고 있을 책임이 있다. 어떤 책임을 수행하기 위해서는 그 책임을 수행하는데 필요한 정보도 함께 알아야 할 책임이 있는 것이다.

책임할당
자율적인 객체를 만드는 가장 기본적인 방법은 정보를 가장 잘 알고 있는 전문가에게 그 책임을 할당하는 것이다. 이를 책임 할당을 위한 정보전문가 패턴이라고 부른다.

책임주도설계
책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방법을 책임 주도 설계라고 부른다.
책임을 할당할 때 고려해야 하는 두 가지 요소
1. 메시지가 객체를 결정한다 - 객체에게 책임을 할당하는 데 필요한 메시지를 먼저 식별하고 메시지를 처리할 객체를 나중에 선택하는 것이 중요하다.
2. 행동이 상태를 결정한다 - 객체지향 패러다임에 갓 입문한 사람들이 가장 쉽게 빠지는 실수는 객체의 행동이 아니라 상태에 초점을 맞추는 것이다. 초보자들은 먼저 객체에 필요한 상태가 무엇인지를 결정하고, 그 후에 상태에 필요한 행동을 결정한다. 이런 방식은 객체의 내부 구현이 객체의 퍼블릭 인터페이스에 노출되도록 만들기 때문에 캡슐화를 저해한다.

역할 - 추상화
객체가 어떤 특정한 협력 안에서 수행하는 책임의 집합을 역할이라고 부른다. 예) 배역과 배우. 배역과 배우 사이의 특성은 동일한 배역을 여러 명우 배우들이 연기할 수 있다는 것이다.

캡슐화, 응집도와 결합도
캡슐화의 정도가 응집도와 결합도에 영향일 미친다는 사실을 강조하고 싶다. 캡슐화를 지키면 모듈 안의 응집도는 높아지고 모듈 사이의 결합도는 낮아진다. 캡슐화를 위반하면 모듈 안의 응집도는 낮아지고 모듈 사이의 결합도는 높아진다. 따라서 응집도와 결합도를 고려하기 전에 먼저 캡슐화를 향상시키기 위해 노력하라. 캡슐화는 설계의 제1원리다.

책임 주도 설계를 향해
데이터보다 행동을 먼저 결정하라. 데이터 중심의 설계에서는 이 객체가 포함해야 하는 데이터가 무엇인가를 결정한 후에 데이터를 처리하는 데 필요한 오퍼레이션은 무엇인가를 결정한다. 반면 책임 중심의 설계에서는 이 객체가 수행해야 하는 책임은 무엇인가를 결정한 후에 이 책임을 수행하는 데 필요한 데이터는 무엇인가를 결정한다.

협력이라는 문맥 안에서 책임을 결정하라
협력을 시작하는 주체는 메시지 전송자이기 때문에 협력에 적합한 책임이란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다. 다시 말해서 메시지를 전송하는 클라이언트의 의도에 적합한 책임을 할당해야 한다는 것이다. 객체를 결정한 후에 메시지를 선택하는 것이 아니라 메시지를 결정한 후에 객체를 선택해야 한다.
객체를 가지고 있기 때문에 메시지를 보내는 것이 아니다. 메시지를 전송하기 때문에 객체를 갖게 된 것이다.

퍼블릭 인터페이스
디미터법칙 - 객체의 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하라는 것이다. 오직 하나의 도트만 사용하라는 말로 요약되기도 한다. 무비판적으로 디미터 법칙을 수용하면 퍼블릭 인터페이스 관점에서 객체의 응집도가 낮아질 수도 있다. 기차충돌처럼 보이는 코드라도 객체의 내부 구현에 대한 어떤 정보도 외부로 노출하지 않는다면 그것은 디미터 법칙을 준수한 것이다.
묻지말고 시켜라 - 절차적인 코드는 정보를 얻은 후에 결정한다. 객체지향 코드는 객체에게 그것을 하도록 시킨다. 내부의 상태를 묻는 오퍼레이션을 인터페이스에 포함시키고 있다면 더 나은 방법은 없는지 고민해 보라. 내부의 상태를 이용해 어떤 결정을 내리는 로직이 객체 외부에 존재하는가? 그렇다면 해당 객체가 책임져야 하는 어떤 행동이 객체 외부로 누수된 것이다.
의도를 드러내는 인터페이스 - 무엇을 하는지를 드러내는 이름은 코드를 읽고 이해하기 쉽게 만들뿐만 아니라 유연한 코드를 낳는 지름길이다.
명령-쿼리 분리

순수한 가공물에게 책임 할당하기
크레이그 라만은 시스템을 객체로 분해하는 데는 크게 두 가지 방식이 존재한다고 설명한다. 하나는 표현적 분해이고 다른 하나는 행위적 분해다. 표현적 분해는 도메인 모델에 담겨 있는 개념과 관계를 따른다. 그러나 종종 도메인 개념을 표현하는 객체에게 책임을 할당하는 것만으로는 부족한 경우가 발생한다. 모든 책임을 도메인 객체에게 할당하면 낮은 응집도, 높은 결합도, 재사용성 저하와 같은 심각한 문제점에 봉착하게 될 가능성이 높아진다. 이 경우 도메인 개념을 표현한 객체가 아닌 설계자의 편의를 위해 임의로 만들어낸 가공의 객체에게 책임을 할당해서 문제를 해결해야 한다. 크레이그 라만은 이처럼 책임을 할당하기 위해 창조되는 도메인과 무관한 인공적인 객체를 순수한 가공물이라고 부른다. 순수한 가공물은 표현적 분해보다 행위적 분해에 의해 생성되는 것이 일반적이다.
이런 측면에서 객체지향이 실세계의 모방이라는 말은 옳지 않다. 만약 도메인 개념이 만족스럽지 못하다면 주저하지 말고 인공적인 객체를 창조하라. 객체지향이 실세계를 모방해야 한다는 헛된 주장에 현혹될 필요가 없다. 우리가 애플리케이션을 구축하는 것은 사용자들이 원하는 기능을 제공하기 위해서지 실세계를 모방하거나 시뮬레이션하기 위한 것이 아니다.

유연성에 대한 조언
유연한 설계는 유연성이 필요할 때만 옳다 - 유연상은 항상 복잡성을 수반한다. 유연하지 않은 설계는 단순하고 명확하다. 유연한 설계는 복잡하고 암시적이다. 설계가 유연할수록 클래스 구조와 객체 구조 사이의 거리는 점점 멀어진다. 따라서 유연함은 단순성과 명확성의 희생 위에서 자라난다. 단순하고 명확한 해법이 그런대로 만적스럽다면 유연성을 제거하라. 유연성은 코드를 읽는 사람들이 복잡함을 수용할 수 있을 때만 가치가 있다.
협력과 책임이 중요하다 - 초보자가 자주 저지르는 실수 중 하나는 객체의 역할과 책임의 자리를 잡기 전에 너무 성급하게 객체 생성에 집중하는 것이다. 중요한 비지니스 로직을 처리하기 위해 책임을 할당하고 협력의 균형을 맞추는 것이 객체 생성에 관한 책임을 할당하는 것보다 우선이다. 불필요한 싱글턴 패턴은 객체 생성에 관해 너무 이른 시기에 고민하고 결정할 때 도입되는 경향이 있다. 핵심은 객체를 생성하는 방법에 대한 결정은 모든 책임이 자리를 잡은 후 가장 마지막 시점에 내리는 것이 적절하다는 것이다.

언제 상속을 사용해야 하는가?
상속을 사용하는 일차적인 목표는 코드 재사용이 아니라 타입 계층을 구현하는 것이어야 한다. 타입 사이의 관계를 고려하지 않은 채 단순히 코드를 재사용하기 위해 상속을 사용해서는 안 된다.
마틴 오더스키는 다음과 같은 질문을 해보고 두 질문에 모두 "예"라고 답할 수 있는 경우에만 상속을 사용하라고 조언한다.
1. 상속 관계가 is-a 관계를 모델링하는가?
2. 클라이언트 입장에서 부모 클래스의 타입으로 자식 클래스를 사용해도 무방한가?

is-a관계 - 생각처럼 직관적이고 명쾌한 것은 아니다. 어휘적인 정의가 아니라 기대되는 행동에 따라 결정해야 한다. 어휘적으로 펭귄은 새지만 새의 정의에 날 수 있다는 행동이 포함된다면 펭귄은 새의 서브타입이 될 수 없다. 어떤 두 대상을 언어적으로 is-a라고 표현할 수 있더라도 일단은 상속을 사용할 예비 후보 정도로만 생각하라.
행동 호환성 - 개념적으로 어떤 연관성이 있다고 하더라도 행동에 연관성이 없다면 is-a 관계를 사용하지 말아야 한다. 행동이 호환될 경우에만 타입 계층으로 묶어야 한다. 여기서 중요한 것은 행동의 호환 여부를 판단하는 기준은 클라이언트의 관점이라는 것이다. 자연어에 현혹되지 말고 요구사항 속에서 클라이언트가 기대하는 행동에 집중하라.

Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg

정말 죄송하지만, 여러분이 얼마나 열심히 노력했는지는 1도 중요하지 않아요.

 Jini     오전 11:46     일상, 자기계발, 책     No comments   

커리어리앱에서 본 글인데 자극적인 제목이긴 하지만 맞는 말 이라고 생각한다.

1. 목표를 달성하는 사람들은, (탁월한 성취를 이루어내는 사람들은), '공헌'에 초점을 맞춘다. 자신이 지금 하고 있는 일에서 더 높은 곳을 바라보고, 목표를 달성하기 위해 자기 자신이 아니라  외부로 눈을 놀린다.

2. 그들은 다음과 같은 질문을 한다. "내가 속한 조직이 성과를 올리고 좋은 결과를 내는 데 나는 어떤 공헌을 할 수 있는가?"

3. 목표를 달성하는 사람들은 책임을 중요하게 여기며, 이렇게 공헌에 초점을 맞추는 것이 목표 달성의 열쇠다.

4. 하지만 대부분의 평범한 지식노동자들은 자기 능력보다 낮은 수준에 초점을 맞추는 경향이 있다. 그리고 이들은 "결과"가 아니라, "노력" 자체에 더 관심을 가진다.

5. 즉, 이들은 어떤 결과를 만들어냈는지가 아니라, 자신이 얼마나 노력했는지를 알아주기를 바란다.

6. 그 결과, 이들은 목표를 달성하지 못한다. 그리고 직함과 지위가 아무리 높아도, 공헌과 책임이 아니라 "자기 얼마나 노력했는가"에만 초점을 맞추는 사람든 결국에는 다른 사람의 부하에 지나지 않는다.

7. 그러나 공헌과 기여에 초점을 맞추고 결과에 책임지는 사람은 아무리 하위 관리자라도 진정한 의미에서 "최고 경영자"다. 그는 조직 전체의 성과에 대해 스스로 책임감을 느끼는 사람이기 때문이다.

8. 특히 자신보다 큰 조직에 공헌할 목표에 초점을 맞추면 자신의 전문 분야, 한정된 기술, 그리고 자신이 속한 부서에만 관심을 두던 지식노동자도 조직 전체의 성과로 관심을 넓힌다. 왜냐하면 외부 세계야말로 결과가 있는 곳이기 때문이다.

9. 그러다 보면 자연스럽게 자신이 얼마나 노력했는지가 아니라 소비자, 단골 고객, 환자의 입장에서 생각하게 된다. 그게 조직이 존재하는 궁극적인 이유이기 때문이다. 그렇게 자기 자신의 노력이 아니라, 더 넓은 관점에서 세상을 바라보게 된다.

10. 즉 탁월한 성취를 이루는 사람들은 "자신이 얼마나 노력했는가" 따위에 매몰되지 않는다. 그 노력이 사람들에게 어떤 기여, 어떤 공헌을 하고 있는지를 살펴보고 분석한다. 그래서 그들은 얼마나 노력했는지가 아니라, 어떤 기여를 했는지를 말한다.

11. 바꿔 말해, 아무리 열심히 노력해도 기여한 것이 없다면 잔인하더라도 그건 별 의미가 없다. 그리고 이를 받아들일 수 있어야 더 나은 방식으로 일을 할 수 있다.

- 피터 드러커 / 자기경영노트 중


일반 조직원의 입장에서 조직기여, 외부세계 공헌과 같은 것은 와닿지 않을 수도 있다고 생각한다. 하지만 노력과 기여에 초점을 맞춰서 생각해보면 그 동안 나도 노력에 초점을 맞추는 경우가 더 많지 않았나 생각이 든다.

예를 들어 보통의 조직원들은(나 역시도) 회사 평가에 대해서 이렇게 생각한다.
"내가 얼마나 열심히 했는데 평가는 이것밖에 안주나?"

그런데 글을 읽고 가만히 생각해보면 나는 회사에 어떠한 기여를 했다고 당당히 말할 수 있을까 라는 생각을 하게 된다. 물론 평가체계까지 이상한 것을 내 탓이라 할 수는 없다. 하지만 당당하게 내가 어떤 성과를 냈다고 말할 수 있어야 평가체계는 물론 회사를 탓할 수 있지 않을까 라는 생각을 해본다. 내가 얼마나 열심히 했는데라는 말은 사실 회사 입장에서 의미는 없는 것 같다. 노력은 많은 사람이 하고 있으니 말이다.

실제 하고 싶은 얘기는 평가에 대한 것은 아니다. 일상 생활에서도 주로 노력에만 집중하지 않았나 하는 생각을 하게 됐다. 간단하게 책을 읽는다고 해보자. 보통은 책을 읽는 행위(노력)에 초점을 맞추는 경우가 많다. "난 이 책을 읽었다" 라는 행위(노력)에 말이다.

하지만 위 글을 적용해보면 내가 책을 읽는 노력을 통해서 얻은 성과는 무엇이냐? 에 초점을 맞춰서 책을 읽는게 맞지 않을까 생각해본다. 그 성과가 단순히 감동을 얻었음도 괜찮고, 기억에 남은 한 단락이 될 수도 있다. 성과의 크고 작음은 큰 문제는 아니라 생각한다. 중요한 것은 노력이 아니라 성과라는 것을 기억하는 것이다. 그렇게 보면 성과=목표 라고 볼 수도 있을 것 같다. 하지만 다른 점은 목표라고 하면 미리미리 세워야 하는 것, 거창해야 할 것 같고 작은 일에 하기에는 좀 오버스러운 것 같다고 생각되는 반면, 성과는 내가 행위를 하는 중에도 혹은 그 이후에도 생각해 볼 수 있는 것이라 목표보다 덜 거창하고 덜 번거로운 것 같다.

노력도 중요하지만 성과라는 관점에서 접근해보는 습관을 들여보는 것도 재미있을 것 같다.

Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg

순수한 가공물에게 책임 할당하기

 Jini     오후 10:21     객체지향     No comments   

 부제 : 객체지향이 실세계의 모방이라는 말에 대하여

객체를 얘기할 때 실세계에 존재하는 무엇과 연관지으라는 얘기들을 많이 한다. 하지만 막상 클래스를 설계하고 객체를 생성하다보면 실세계와 맞지 않는 경우가 많이 생긴다. 이게 문제 되는 것은 항상 나를 의심하게 만들고 완성 이후에도 무언가 찝찝함이 남는다는 점이다. 

이런 나의 찝찝함을 덜어주는 내용이 있어 공유해본다.

크레이그 라만은 시스템을 객체로 분해하는 데는 크게 두 가지 방식이 존재한다고 설명한다. 하나는 표현적 분해이고 다른 하나는 행위적 분해다.

표현적 분해는 도메인 모델에 담겨 있는 개념과 관계를 따른다. 그러나 종종 도메인 개념을 표현하는 객체에게 책임을 할당하는 것만으로는 부족한 경우가 발생한다.

모든 책임을 도메인 객체에게 할당하면 낮은 응집도, 높은 결합도, 재사용성 저하와 같은 심각한 문제점에 봉착하게 될 가능성이 높아진다. 이 경우 도메인 개념을 표현한 객체가 아닌 설계자가 편의를 위해 임의로 만들어낸 가공의 객체에게 책임을 할당해서 문제를 해결해야 한다. 크레이그 라만은 이처럼 책임을 할당하기 위해 창조되는 도메인과 무관한 인공적인 객체를 PURE FABRICATION(순수한 가공물)  이라고 부른다.

(중략)

먼저 도메인이의 본질적인 개념을 표현하는 추상화를 이용해 애플리케이션을 구축하기 시작하라. 만약 도메인 개념이 만족스럽지 못하다면 주저하지 말고 인공적인 객체를 창조하라. 객체지향이 실세계를 모방해야 한다는 헛된 주장에 현혹될 필요가 없다. 우리가 애플리케이션을 구축하는 것은 사용자들이 원하는 기능을 제공하기 위해서지 실세계를 모방하거나 시뮬레이션하기 위한 것이 아니다.

출처 : 오브젝트 / 코드로 이해하는 객체지향 설계 / 조영호 지음

현실/도메인 개념과 맞지 않는 객체가 나오는 것은 자연스러운 현상이라는 것을 기억하자.


Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg

키크론 K8 Pro VIA 프로그램 인식

 Jini     오후 5:21     키보드, 키크론, K8 PRO RGB, troubleshooting     No comments   

•케이블 모드 설정으로 바꾸고 USB 케이블 연결 후 VIA 프로그램 실행
•DESIGN 탭에서 Use V2 definitions(deprecated)를 on시키고 JSON 파일을 LOAD
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg

MongoDB 모델링

 Jini     오후 7:46     mongodb     No comments   

도큐먼트 크기

  1. 아주 빈번하게 변경되는 데이터만 분리하는 것은 안정적 서비스를 위해 고려해볼 만하다.
  2. 기능별로 조회되는 부분이 완전히 다르다면 (액세스 패턴이 다르다면) 분리하는 것도 좋은 방법이다.
  3. 각 필드를 그룹핑해서 서브 도큐먼트를 만들고 응용프로그램에서 필요 서브도큐먼트만 선별해서 가져가는 것이 네트워크 사용량을 줄이는데 도움이 될 것이다.
    (뒤에 조금 더 자세히 설명한다.)

정규화(Document Referencing) vs 역정규화(Embedding)

  1. 역정규화는 데이터가 얼마나 커지는지, 데이터를 어떻게 읽어가는지에 따라 할지 말지 결정해라.
  2. 가능하면 몽고DB도 정규화를 사용하라. join이 안된다고 Embedding을 먼저 생각하지는 말자.

서브 도큐먼트

  1. 데이터를 성격별로 묶어서 그룹핑하는 것도 고려하자.
    • 서브 도큐먼트 없이 일반 필드로만 구성
      {
          _id: 1,
          user_name: "matt.lee",
          user_real_name: "SeongUck Lee",
          
          contact_office_number: "010-xxxx-xxxx",
          contact_house_number: "02-xxx-xxxx",
          
          address_zip_code: "00000",
          address_detail:"ABC Apt Seongsu-1ga",
          address_city: "Seoul",
          address_country: "Korea",
          ...
      }
      
    • 서브 도큐먼트로 필드 그룹
      {
          _id: 1,
          user_name: "matt.lee",
          user_real_name: "SeongUck Lee",
          
          contact: {
            office_number: "010-xxxx-xxxx",
            house_number: "02-xxx-xxxx"
          },
          
          address: {
            zip_code: "00000",
            detail: "ABC Apt Seongsu-1ga",
            city: "Seoul",
            country: "Korea"
          },
          ...
      }
      
  2. 다음과 같은 장점이 있다.
    • 도큐먼트의 가독성과 식별성을 높여줄 수 있다.
    • 필드의 이름에서 반복된 단어를 생략할 수 있다.
    • 미세하지만 성능적인 장점도 얻을 수 있다.

인덱스

  1. 인덱스는 가능하면 "ESR" Rule대로 만들자(E:Equal, S:sort, R:range)
  2. 불필요한 인덱스는 만들지 말자. 인덱스 생성으로 인해 느려질 수 있다.
  3. 몽고의 Sort는 메모리에서 일어나며 sort를 위해 일반적으로 32mb의 공간만 할당하고 있다. 즉 32mb 이상을 읽어서 sort하면 에러가 발생한다. 이런 이유로 sort는 index를 이용하는 것을 추천한다.

배열

  1. 제한 없이 증가하는 데이터면 사용하지 말 것.
  2. 배열 관련 연산자는 $push, $pop이 성능상 좋다. $addToSet이나 $pull 연산이 빈번한 모델이면 배열 타입 사용은 한 번 더 고민해보자.
  3. 배열이 너무 크면 oplog 생성으로 인한 부하가 크다. 배열 사이즈는 적당히 유지되어야 한다.

필드 이름

  1. 데이터양이 아주 많은 경우 긴 필드이름은 성능에 영향을 미칠 수 있다.

도큐먼트 유효성

  1. 몽고DB는 컬렉션에 속한 필드 값에 대해서는 기본적으로 어떠한 제약도 가지지 않지만 필요시 RDBMS에서와 같은 정규화된 제약을 설정할 수 있다.
  2. 유효성 체크 규칙은 컬렉션 생성할 때 뿐만 아니라 이미 사용되고 있는 컬렉션에 대해서도 설정 가능하다.

조인

  1. 몽고DB는 기본적으로 조인을 지원하지 않았으나 3.2 버전부터는 $lookup이라는 보조적인 조인 기능을 제공한다.
  2. 하지만 몇 가지 제약사항이 있다.
    • INNER JOIN은 지원하지 않으며, OUTER JOIN만 지원한다.
    • 조인되는 대상 컬렉션은 같은 데이터베이스에 있어야 한다.
    • 샤딩되지 않은 컬렉션만 "$lookup" 오퍼레이션을 사용할 수 있다.

[출처]
대용량 데이터 처리를 위한 Real MongoDB / 위키북스 / 이성욱 지음
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg

Java 버전별 특징 및 변경사항

 Jini     오후 10:28     JAVA     No comments   

1. Java7

• 타입추론

List<String> list = new ArrayList<>();

• 이진수 리터럴, 숫자 리터럴에 _ 지원

• Switch문 문자열 가능

• try-with-resources 문 : AutoCloseable 인터페이스를 구현하는 클래스에 속하는 경우 다음과 같은 코드 패턴에 대한 단축 기능을 제공한다.

//JAVA 7 이전
//리소스를 연다
try {
    리소스를 이용해 작업한다.
}
finally {
    리소스를 닫는다.
}

//JAVA 7 이후
try (Resource res = ...) {
    res를 이용해 작업한다.
}

//여러 리소스를 지정할 수 있다.
try (Scanner in = new Scanner(Paths.get("/usr/share/dict/words"));
      PrintWriter out = new PrintWriter("/tmp/out.txt")) {
    while (in.hasNext()) {
      out.println(in.next().toLowerCase());
    }
}

• 여러 예외 잡기


try {
  //예외를 던질 수 있는 코드
}
catch (FileNotFoundException | UnknownHostException ex) {
  //파일 누락 및 알려지지 않은 호스트에 대한 긴급 액션
}
catch (IOException ex) {
  //그 외의 모든 I/O 문제에 대한 긴급 액션
}

2. Java8

• 32비트를 지원하는 마지막 공식 버전

• Lambda

• Stream

• Default Method

• LocalDate, LocalTime

• Optional


3. Java9

• default GC : G1GC

• Module System

• Collections of(불변)

List<String> list1 = List.of("a", "b");

• Jshell 추가

• try-with-resources 향상

// try() block 밖에 선언된 변수에 대해서는 try-with-resources 사용불가능했으나 java9부터 가능
// BufferedReader is declared outside try() block
BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));

// Java 9 make it simple
try (br) {
    String line;
    while (null != (line = br.readLine())) {
        // processing each line of file
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

• 인터페이스에 private 메소드 사용가능


4. Java10

• var 사용가능

• JVM 힙 영역을 시스템 메모리가 아닌 다른 종류의 메모리에도 할당 할 수 있게 되었다.


5. Java11

• 새로운 가비지 컬렉터 등장 : ZGC, Epsilon

Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg

WebFlux Error Handling

 Jini     오후 10:07     error, exception, Webflux     No comments   

WebFlux Error Handling

  • doOnError : 예외 발생시 특정행위를 수행한다.
  • onErrorReturn : 예외 발생시 특정 값을 return 한다.
  • onErrorResume : 예외 발생시 다른 Flux형태로 return 한다.
  • onErrorContinue : 예외 발생시 멈추지 않고 해당 영역만 skip 한다(별도 처리 하지 않는 이상 정상 응답을 return한다).
  • onErrorMap : 예외 발생시 다른 Exception으로 변환한다.

doOnError

Source:
@RequestMapping("/error/test")
public Flux<Integer> getNum() {
  return Flux.range(0, 5)
      .map(x -> {
        if (x == 3) {
          throw new IllegalArgumentException("invalid num");
        }
        return x;
      })
      .doOnError(x -> log.error("num generate error"))
      .log();
}
Result:

 INFO 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : | onSubscribe([Fuseable] FluxPeekFuseable.PeekFuseableSubscriber)
 INFO 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : | request(unbounded)
 INFO 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : | onNext(0)
 INFO 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : | onNext(1)
 INFO 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : | onNext(2)
ERROR 5276 --- [ctor-http-nio-2] c.e.demo.r4.controller.R4Controller      : num generate error
ERROR 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : | onError(java.lang.IllegalArgumentException: invalid num)
ERROR 5276 --- [ctor-http-nio-2] reactor.Flux.PeekFuseable.1              : 

onErrorReturn

Source:

@RequestMapping("/error/test")
public Flux<Integer> getNum() {
  return Flux.range(0, 5)
      .map(x -> {
        if (x == 3) {
          throw new IllegalArgumentException("invalid num");
        }
        return x;
      })
      .onErrorReturn(99)
      .log();
}
Result:

 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onSubscribe(FluxOnErrorResume.ResumeSubscriber)
 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : request(unbounded)
 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(0)
 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(1)
 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(2)
 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(99)
 INFO 12068 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onComplete()

onErrorResume

Source:

@RequestMapping("/error/test")
public Flux<Integer> getNum() {
  return Flux.range(0, 5)
      .map(x -> {
        if (x == 3) {
          throw new IllegalArgumentException("invalid num");
        }
        return x;
      })
      .onErrorResume(exec -> {
        log.error("num generate error");
        return Mono.just(99); //어떤 값으로 return을 할지 상황에 맞게 지정한다.
      })
      .log();
}
Result:

 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onSubscribe(FluxOnErrorResume.ResumeSubscriber)
 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : request(unbounded)
 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(0)
 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(1)
 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(2)
ERROR 8444 --- [ctor-http-nio-2] c.e.demo.r4.controller.R4Controller      : num generate error
 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(99)
 INFO 8444 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onComplete()

OnErrorContinue

Source:

@RequestMapping("/error/test")
public Flux<Integer> getNum() {
  return Flux.range(0, 5)
      .map(x -> {
        if (x == 3) {
          throw new IllegalArgumentException("invalid num");
        }
        return x;
      })
      .onErrorContinue((exec, num) ->
          log.error("num generate error, number is : {}, error msg : {}", num, exec.getMessage()))
      .log();
}
Result:

 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | onSubscribe([Fuseable] FluxContextStart.ContextStartSubscriber)
 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | request(unbounded)
 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | onNext(0)
 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | onNext(1)
 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | onNext(2)
ERROR 9728 --- [ctor-http-nio-2] c.e.demo.r4.controller.R4Controller      : num generate error, number is : 3, error msg : invalid num
 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | onNext(4)
 INFO 9728 --- [ctor-http-nio-2] reactor.Flux.ContextStart.1              : | onComplete()

onErrorMap

Source:

@RequestMapping("/error/test")
public Flux<Integer> getNum() {
  return Flux.range(0, 5)
      .map(x -> {
        if (x == 3) {
          throw new IllegalArgumentException("invalid num");
        }
        return x;
      })
      .onErrorMap(exec -> {
        log.error("num generate error, error msg : {}", exec.getMessage());
        throw new RuntimeException("change error type");
      })
      .log();
}
Result:

 INFO 14204 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onSubscribe(FluxOnErrorResume.ResumeSubscriber)
 INFO 14204 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : request(unbounded)
 INFO 14204 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(0)
 INFO 14204 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(1)
 INFO 14204 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onNext(2)
ERROR 14204 --- [ctor-http-nio-2] c.e.demo.r4.controller.R4Controller      : num generate error, error msg : invalid num
ERROR 14204 --- [ctor-http-nio-2] reactor.Flux.OnErrorResume.1             : onError(java.lang.RuntimeException: change error type)

[참고링크]
[Webflux Tip] 3. Webflux Error 처리! . (n.d.). https://akageun.github.io/2019/07/26/spring-webflux-tip-3.html.
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Google+
  •  Stumble
  •  Digg
이전 게시물 홈

Popular Posts

  • Redmine Text Format
    1. 글자색상 변경 %{color:red}dev% 2. 음영색상 변경 %{background:lightgreen} lightgreen% 3. 문단 넘버링(띄어쓰기 주의) # 큰 제목 ## 큰제목의 하위 제목 # 두번째 큰 제목 # ...
  • 오라클 한글깨짐 현상해결
    1. 레지스트리 편집기 실행 : 시작 -> 실행 -> regedit 2. HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE 하위 경로 폴더중 이름이 "NLS_LANG"인 속성의 데이터 확인 3. "...
  • 오브젝트 : 코드로 이해하는 객체지향 설계
    오브젝트 - 코드로 이해하는 객체지향 설계 / 조영호 지음 / 위키북스 객체지향에 대해 그 동안 잊고 있었던 것들을 상기시켜주고 새로운 인사이트를 줬으며 그 동안의 설계에 대해 돌이켜 보게 해준 유익한 책. 객체 사이의 의존성을 완전히 없애는 것이 정...
  • New Features Java 1.7(JDK 1.7)
    ■ The New Objects Class   1) Objects.requireNonNull(T), Objects.requireNonNull(T, String)     #. 아래 Person 객체 생성시 newLastName이나 newFirstNa...
  • MongoDB Array Query(With MongoTemplate)
    Mongo Collection 구조 컬렉션명 : bookstore { "_id": "1234567890", "books": [ { "bookId": ...

Recent Posts

Recent Posts Widget

Blog Archive

  • ▼  2023 (4)
    • ▼  3월 (1)
      • 오브젝트 : 코드로 이해하는 객체지향 설계
    • ►  2월 (1)
    • ►  1월 (2)
  • ►  2022 (1)
    • ►  2월 (1)
  • ►  2020 (8)
    • ►  7월 (1)
    • ►  4월 (3)
    • ►  3월 (4)
  • ►  2018 (1)
    • ►  7월 (1)
  • ►  2015 (1)
    • ►  5월 (1)
  • ►  2014 (5)
    • ►  8월 (1)
    • ►  7월 (1)
    • ►  6월 (1)
    • ►  5월 (1)
    • ►  1월 (1)
  • ►  2013 (10)
    • ►  12월 (1)
    • ►  11월 (1)
    • ►  9월 (2)
    • ►  8월 (3)
    • ►  7월 (3)
  • ►  2012 (1)
    • ►  3월 (1)

Categories

  • 객체지향 (1)
  • 도서요약 (1)
  • 문법에서 문장까지 (2)
  • 일상 (1)
  • 자기계발 (1)
  • 책 (1)
  • 키보드 (1)
  • 키크론 (1)
  • blogspot (2)
  • error (1)
  • exception (1)
  • GIT (1)
  • JAVA (6)
  • JUNIT (1)
  • K8 PRO RGB (1)
  • kafka (1)
  • markdown (1)
  • mongodb (2)
  • mongotemplate (1)
  • optional (1)
  • Oracle (4)
  • Redmine (1)
  • spring (1)
  • stackedit (1)
  • troubleshooting (1)
  • Visual Studio (1)
  • Webflux (1)

Unordered List

Pages

  • 홈

Text Widget

Categories

Tags

Facebook

  • Home
  • Features
  • _Multi DropDown
  • __DropDown 1
  • __DropDown 2
  • __DropDown 3
  • _ShortCodes
  • _SiteMap
  • _Error Page
  • Documentation
  • Video Documentation
  • Download This Template

Footer Menu Widget

  • Home
  • About
  • Contact Us

Social Plugin

JINI. Powered by Blogger.

Copyright © Jini's Blog | Powered by Blogger
Design by Hardeep Asrani | Blogger Theme by NewBloggerThemes.com | Distributed By Gooyaabi Templates