인덱스를 생성할 때의 기준 

 

    - 사용자에 의해 사용되는 어플리케이션과 SQL과 Query에 인덱스를 생성


    - where절에서 빈번하게 사용되는 컬럼에 인덱스를 생성


    - 자주 join 되는 테이블 컬럼에 인덱스를 생성


    - whwere절에서 함수와, 연산으로 사용되는 컬럼에는 인덱스를 만들지 않는다.


    - 외래키와 whwere절에서 빈번하게 사용되는 컬럼에는 nonunique 인덱스를 생성


    - 테이블의 크기가 적은 것은 인덱스를 만들지 않는다.


    - 인덱스가 많은 경우 오버헤드를 발생시킬 수 있다.


    - Select 절의 컬럼을 인덱스 컬럼으로 만들 수 있다(성능 Up)


    - 칼럼의 분포도가 (10 ~15 %)이하인 경우 적용. 단 분포도가 범위 이상이더라도 부분범위 처리를 목적으로 하는경          우 인덱스 적용 (같은 값을 가지는 row가 적은 비율을 가지는 칼럼)

DML을 이용하여 자료를 다룰 때는 항상 NULL을 염두에 두고 다루어야 한다.
NUMBER 형 자료를 NULL과 연산하면 결과는 항상 NULL이 된다.
NULL이 포함될 유려가 있는 칼럼을 이용할 때는 항상 NVL 함수를 이용하여 값을 치환시켜 사용하는 습관을 들여야 한다.

일반 적으로 같은 지 비교 : WHERE A = '1'
           다른 지 비교 : WHERE a <> '1'

NULL 비교 : WHERE A IS NULL
            WHERE A IS NOT NULL

            SELECT EMP NAME FROM TEMP WHERE NVL(HOBBY, ’ 등산’ ) = ’등산’ ;

ALIAS
    동일한 컬럼 이 두개 테이블 이상에 존재할 때 어떤 테이블의 컬럼 인지를 명시하지 않으 에러가 나게 된다. 그래서 ALIAS를 사용함

UNION : 합집합을 구해준다(중복 자료 배제)
UNION ALL : 합집합을 구해준다(중복 자료 포함)
MINUS : 차집합을 구해준다.
INTERSECT : 교집합을 구해준다.

UNION ALL 빼고 SORT 가 일어난다.
(mode에 따라 다름)

CORRELATED 서브쿼리 
    CORRELATED 서브쿼리는 SUB QUERY 가 MAIN QUERY 의 값을 이용하고, 그 렇게 구해진 SUB QUERY의 값을 다시 MAIN QUERY가 다시 이용하게 된다 

    SELECT EMP ID,EMP_NAME FROM TEMP A WHERE SALARY > (SELECT AVG(SALARY) FROM TEMP B WHERE B.LEV = A.LEV)

ROWNUM
    ORDER Bγ 후에 ROWNUM이 붙는 것이 아니고, 조건 절 을 만족시킨 행들에 ROWNUM이 붙은 후 ORDER BY가 이루어진다.

ROWID
    ROWID는 DATABASE내의 모든 ROW가 가지는 유일한 식별자이다.

NOT IN
    NOTIN 연산자에 NULL이 포함되면 어떠한 경우 일지라도 한건도 DATA를 검색하지 못 한다. 
    WHERE HOBBY <> NULL AND HOBBY <> ’ 낚시 ’ ; 

HIERACHICAL SELECT 
    자료의 구조가 계층적으로 이루어진 경우 상위자료에서부터 하위자료로의 자료전개 및 하위자료에서 상위자료로의 역 전개를 위하여 사용되는 SELECT 형식이다
    SELECT LEVEL, DEPT CODE, DEPT N.따‘E FROM TDEPT CONNECT BY PRIOR DEPT CODE = PARENT DEPT START WITH DEPT CODE = ’ 000000 ’; 

.\mvnw spring-boot:run 메이븐 프로젝트 실행 명령어


./gradlew bootRun 그래들 프로젝트 실행 명령어

'Spring' 카테고리의 다른 글

마이크로서비스에서 DDD 사용하기  (0) 2020.03.05
Spring 날짜 타입 변환  (0) 2019.06.24
Spring 동작원리  (0) 2019.02.27
HTTP Status 404 - /WEB-INF 에러  (0) 2019.02.25
Spring MVC 구성 요소  (0) 2019.02.23

- 문서 


    문서는 프로젝트 활동과 관련을 맺고 있어야 한다.

 

    Ubiquitous languzge언어로 작성하라

 

    문서를 최소한으로 유지하고 대화를 보완하는 데 집중하라

 

    문서는 유요한 상태를 유지하고 최신 내용을 담고 있어야 한다.

 

- 하나의 모델이 구현, 설계, 의사소통의 기초가 되야 한다

 

- 설명을 위한 모델!!

 

- 모델과 설계를 연계한는 것이 실용적이다.

 

- 소프트웨어 시스템의 일부를 설계할 때는 도메인 모델을 있는 그대로 반영해서 설계와 모델의 대응을 분명하게 하라. 또한 모델을 재검토해서 더욱 자연스럽게 소프트웨어로 구현될 수 있게 수정하라

 

- 유비쿼터스 언어를 지원하는 것과 더불어 분석과 설계의 두 가지 측면을 충분히 만족하는 단 하나의 모델을 만들어내야 한다.

 

- DDD에서는 모든 단일 컨텍스트 내에서 오로지 하나의 모델을 다룰 것을 요구한다.

 

- 코드의 변경이 곧 모델의 변경이다. 

 

- 도메인의 격리

    시스템에서 도메인과 관련이 적은 기능으로부터 도메인 객체를 분리할 필요가 있다. 이러한 기법을 Layered architecture(계층형 아키텍처) 이라고 한다.

 

    매우 복잡한 작업을 처리하는 소프트웨어를 만들 경우 관심사의 분리가 필요하며, 이로써 격리된 상태에 있는 각 설계 요소에 집중할 수 있다. 동시에 시스템 내의 정교한 상호작용은 

    그러한 분리와는 상관없이 유지돼야 한다.

 

    계층화의 핵심 원칙은 한 계층의 모든 요소는 오직 같은 계층에 존재하는 다른 요소나 계층상 '아래'에 위치한 요소에만 의존한다는것이다 위로 거슬러 올라가는 의사소통은 반드시 간적접인 메커니즘을 

    거처야 한다.

 

    4가지 계층으로 이루어짐                                                                                                                  

    사용자 인터페이스 : 사용자에게 정보를 보여주고 사용자의 명령을 해석하는 일을 책임진다.

    응용계층 : 소프트웨어가 수행할 작업을 저으이하고 표현력 있는 도메인 객체가 문제를 해결하게 한다. 이 계층에서 책임지는 작업은 업무상 중요하거나 다른 시스템의 응용 계층과 상호작용하는데 필요한 것들이다.

    도메인 계층 : 업무 개념과 업무 상황에 관한 정보, 업무 규칙을 표현하는 일을 책임진다.

    인프라스트럭쳐 계층 상위 계층을 지원하는 일반화된 기술적 기능을 제공한다. 메시지 전송, 도메인 영속화, UI위젯을 그리는 것등 

 

    - 복잡한 프로그램을 여러 개의 계층으로 나누어라

    - 상위 계층과의 결합을 느슨하게 유지하라.

    - 도메인 객체는 도메인 모델을 표현하는 것에만 집중 할 수 있다.

    

- 계층 간 관계 설정

    각 계층은 설계 의존성을 오직 한 방향으로만 둬서 느슨하게 결합된다. 

    하위 수준의 객체가 상위 수준의 객체와 소통해야 할 경우 콜백이나 ovserver패턴처럼 계층 간에 관계를 맺어주는 아키텍처 패턴을 활욜 할 수 있다.

 

-smart ui 안티패턴

    모든 업무 로직을 사용자 인터페이스에 넣어라. 애플리케이션을 작은 기능으로 잘게 나누고, 나눈 기능을 각기 분리된 사용자 인터페이스로 구현해서 업무 규칙을 분리된 사용자 인터페이스에 들어가게 하라.

 

    단점 

        데이터 베이스를 이용하는 방식 말고는 여러 애플리케이션을 통합하기가 수월하지 않다.

        행위를 재사용하지 않으며 업무 문제에 대한 추상화가 이뤄지지 않는다. 업무 규칙이 적용 되는 연만사다 업무 규칙이 중복된다.

        신속한 프로토타입 작성과 반복주기가 smart ui가 지닌 태생적인 한계에 도달하게 된다. 이는 추상화의 부재로 리팩터링의 여지가 제한되기 때문이다.

        복잡성에 금방 압도되어 애플리케이션의 성장 경로가 순전히 부가적인 단순 응용으로만 향한다 우아한 방법으로 더욱 풍부한 행위를 갖출 수 있는 방법은 없다.

 

-연관관계를 줄여라(다루는 방법)

    1. 탐색 방향을 부여한다.

    2. 한정자를 추가해서 사실상 다중성을 줄인다.

    3. 중요하지 않은 연관관계를 제거한다.

 

- ENTITY

    - 자신의 생명주기 동안 형태와 내용이 급격하게 바뀔 수도 있지만 연속성은 유지해야한다.

    - 식별성이 저의돼 있어야 한다.

    - 사람,도시,자동차,복권티켓,은행거래 등

 

    ex) 경기장의 좌석을 예약하는 애플리케이션에서는 좌석과 참석자를 ENTITY로 다룰 수 있다 지정석인 경우 고유의 좌석번호가 적혀 있을 것이므로 좌석은 유일한 식별자를 갖는다.

        하지만, 입장권을 가진 사람이 빈 좌석을 찾아 아무 데나 앉을 수 있는 "일반석"이라면 개별좌석을 구분하지 않아도 된다. 이 경우 Entity가 아니며 식별자는 필요하지 않다.

 

    - 가장 기본적인 책임은 객체의 행위가 명확하고 예측 가능해질 수 있게 연속성을 확립하는 것이다.

 

- Value Object

    - ENTITY의 식별성을 관리하는 일은 매우 중요하지만 그 밖의 객체에 식별성을 추가한다면 시스템의 성능이 저하되고, 분석 작업이 별도로 필요하며, 모든 객체를 동일한 것으로 보이게 해서 모델이 혼란스러워질 수 있다.

    - 소프트웨어 설계는 복잡성과 끊임없는 전투다. 그러므로 우리는 특별하게 다뤄야 할 부분과 그렇지 않은 부분을 구분해야 한다.

    - 식별성이 없는 것으로만 생각한다면, 추가할 게 그리 많지 않다.

    - 즉, 사물을 서술하는 객체다.

    - 종종 한 연산에서 사용할 목적으로 만들어진 후 폐기되는 것처럼 일시적인 용도로 사용되기도 한다.

 

    모델에 포함된 어떤 요소의 속성에만 관심이 있다면 그것을 VALUE OBJECT로 분류하라.

    VALUE OBJECT는 불변적으로 다뤄라!

 

    ex) 한 객체가 다른 여러 객체에서 참조되고 있다면 그러한 객체 가운데 일부는 가까이에 위치하지 않을 것이므로 데이터를 가져오는 데 물리적인 연산이 추가적으로 필요할 것이다. (동일한 데이터에 여러 개의 사본을 저장하는 기법

    을 역정규화라고하며 접근 시간이 더 중요한 경우에 사용한다.)

 

- MODULE(모듈, 패키지라고 함)

    보통 module을 토대로 모델을 두 가지 측면에서 바라 볼 수 있다, 즉 사람들은 전체에 압도되지 않고도 세부사항을 보거나, 세부 사항을 배제한 상태에서 module 간의 관계를 볼 수 있다.

    모듈간의 결합도는 낮아야 하고 모듈간의 응집도는 높아야한다.(모듈로 쪼개지는 것은 코드가 아닌 개념이다)

    

    모듈은 모델과 함께 발전해야 한다. 

 

- Aggregate

    우리가 데이터 변경의 단위로 다루는 연관 객체의 묶음을 말한다. Aggregate에는 루트와 경계가 있다.

    경계는 Aggregate에 무엇이 포함되고 포함되지 않는지를 정의한다. 루트는 단 하나만 존재하며, Aggregate에 포함된 특정 ENTITY를 가리킨다.

    경계 안의 객체는 서로 참조 할 수 있지만, 경계 바깥의 객체는 해당 Aggregate의 구성요소 가운데 루트만 참조할 수 있다.

    루트 이외의 ENTITY는 지역 식별성을 지니며, 지역 식별성은 Aggregate 내에서만 구분되면 된다. 이는 해당 Aggregatedml 경계 밖에 위치한 객체는 루트 ENTITY의 컨텍스트 말고는 Aggregate의 내부를 볼 수 없기 때문이다.

 

    ENTITY와 VALUE OBJECT를 Aggregate로 모으고 각각에 대해 경계를 정의하라.

    한 ENTITY를 골라 Aggregate의 루트로 만들고 Aggregate 경계 내부의 객체에 데해서는 루트를 거쳐 접근할 수 있게 하라. Aggregate 밖의 객체는 루트만 참조할 수 있게 하라.

    내부 구성요소에 대한 일시적인 참조는 단일 연산에서만 사용할 목적에 한해 외부로 전달될 수 있다. 루트를 경유하지 않고는 Aggregate의 내부를 변경할 수 없다. 이런식으로 Aggregate의 각 요소를 배치하면 Aggregate 안의 객체와

    전체로서의  Aggregate의 상태를 변경할때 모든 불변식을 효과적으로 이행할 수 있다.

 

-FACTORY

    어떤 객체나 전체 Aggregate를 생성하는 일이 복잡해지거나 내부 구조를 너무 많이 드러내는 경우 FACTORY가 캡슐화를 제공해준다.

 

    복잡한 객체와 Aggregated의 인스턴스를 생성하는 책임을 별도의 객체로 옮겨라.

 

    FACTORY를 잘 설계학 위한 두가지 기본 요건

        1. 각 생성 방법은 원자적이어야 한다, 생성된 객체나 Aggregate의 불변식을 모두 지켜야 한다.

        2. 생성된 클래스보다는 생성하고자 하는 타입으로 추상화돼야 한다.

 

- 생성자만으로 충분한 경우

    클래스가 타입인 경우, 인터페이스를 구현하는 식으로 다형적으로 사용되지 않는 경우

    클라이언트가 strategy를 선택하는 한 방법으로서 구현체에 관심이 있는 경우

    클라이언트가 객체의 속성을 모두 이용할 수 있어서 클라이언트에게 노출된 생성자 내에서 객체 생성이 중첩되지 않는 경우

    생성자가 복잡하지 않은 경우

    공개 생성자가 FACTORY와 동일한 규칙을 반드시 준수해야 하는 경우, 이때 해당 규칙은 생성된 객체의 모든 불변식을 충족하는 원자적인 연산이어야 한다.

 

- 인터페이스 설계

    각 연산은 원자적이어야한다.

    FACTORY는 자신에게 전달된 인자와 결합될 것이다. 입력 매개변수를 신경 써야한다. 아니면 의존성의 덫이 만들어질 수 있다.

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

- 명확한 모델을 발견하는 것이다.

 

- 다소 불명확한 개념을 모델링 하는 법

    - 명시적인 제약조건

        흔히 제약조건은 암시적인 상태로 존재하며, 이를 명시적으로 표현하면 서계를 대폭 개선할 수 있다.

        (간단한 불변식의 경우에는 내용물을 변경하는 개별 연산 안에 조건 로직을 사용해서 불변식을 보장할 수 있다,)

        제약조건을 자체적인 메서드로 분리하면 제약조건에 이름을 부여해서 제약조건을 멱확하게 표현할 수 있다.

    - 도메인 객체로서의 프로세스

        알고리즘 자체 또는 그것의 일부를 하나의 객체로 만드는 것이다.

 

-specification 

    다른 객체에 대한 제약조건을 기술하며, 제약조건은 존재할 수도 존재하지 않을 수도 있따.(또, 명시된 기준을 만족하는지 검사할 수 있다)

 

    매우 상이해 보이는 애플리케이션 기능을 하나로 통합해 준다.

    

    1. 객체가 어떤 요건을 충족시키거나 특정 목적으로 사용할 수 있는지 가늠하고자 객체를 검증

    2. 컬렉션 내의 객체를 선택

    3. 특정한 요구사항을 만족하는 새로운 객체의 생성을 명시

 

    1.검증  

    2.선택(또는 질의)   

    3.요청 구축 생성 (specification을 사용해서 생성기의 인터페이스를 정의하면 생성할 결과물을 명시적으로 인터페이스에 포함시킬 수 있따.)

        - 생성기의 구현을 인터페스로부터 분리할 수 있따. specification은 생성할 결과물에 대한 요구사항은 선언하지만 결과물을 생성하는 방법은 정의하지 않는다.

        - specification을 사용한 인터페이스는 생성 규칙을 명시적으로 전해주므로 개발자들이 연산의 세부적인 사항을 이해하지 않고도 생성기의 결과물을 예상할수있따.

        - 생성기는 단순히 specification에 포함된 조건에 따라 객체를 생성하는 반면 생성 요청을 표현하는 코드는 클아이언트에 존재하므로 더 유연한 인터페이스를 얻거나 더 유연하게 개선할 수 있따.

 

유연한 설계를 만들 수 있는 패턴 집합

    -intention-revealing interface(의도를 드러내는 인터페이스)

        도메인 개념을 반영하도록 클래스와 메서드의 이름을 지어야 한다.

        결과와 목적만을 표현하도록 클래스와 연산의 이름을 부여하라

    -side-effect-free function(부수효과가 없는 함수)

        명령과 질의를 엄격하게 분리된 서로 다른 연산으로 유지하는 것이다.

        명령과 질의를 분리하는 대신 value Object를 생성해서 반환한다.

    -assertion

        assertion을 사용하면 명령 entity 부수효과가 명확해지고 다루기 쉬워진다.

    -conceptual contour(개념적 윤곽)

        도메인을 중요 영역을 나누는 것과 관련한 직관을 감안해서 설계요소를 응집력있는 단위로 분해해라. 계속적인 리팩터링을 토대로 변경되는 부분과 변경되지 않는 부분을 나누는 중심 축을 식별하고,

        변경을 분리하기 위한 패턴을 명확하게 표현하는 conceptual contour

    -standalone class(독립형 클래스)

        의존성을 낮춰야 함

        낮은 결합도는 객체 설계의 기본 원리다. 가능한 한 늘 결합도를 낮추고자 노력하라. 현재 싱황과 무관한 모든 개념을 제거하라. 그러면 클래스가 완전히 독립적으로 바뀌고 단독으로 컴토하고 이해할 수 있을 것이다.

    -closure of operation(연산의 닫힘)

        적절한 위치에 반환 타입과 인자 타입이 동일한 연산을 정의하라 구현자가 연산에 사용되는 상태를 포함하고 있다면 연산의 인자로 구현자를 사용하는 것이 효과적이므로 인자의 타입과 반환 타입을 구현자의 타입과 동일하게 정의한다.

        주로 VALUE OBJECT의 연산을 정의하는 데 주로 사용된다.

 

분석 패턴

    -strategy 객체 (분기를 둬서 어떤 policy를 전달하느냐를 결정)

    -composite 내부에 포함된 모든 구성요소를 포괄한느 추상타입을 정의해서 사용하는 것

    -flyweight value object집합이 자주사용 되는 경우 적합

 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

bounded context 

 

context map

 

sharedd kernel(공유 커널)

    밀접하게 연관된 애플리케이션을 대상으로 작업중인 팀 간의 협력이 조율되지 않는다면 잠시 동안은 작업을 진행할 수 있겠지만 각 팀이 만들어낸 결과물을 함께 조합하기는 쉬빚 않을것이다.

    - 두 팀 간에 공유하기로 한 도메인 모델의 부분집합을 명시하라. 여기에는 모데르이 부분집합 뿐만 아니라 모델 요소와 연관된 코드나 데이터베이스 설계의 부분집합까지도 포함된다.

    - 명시적으로 공유하는 부분들은 특별한 상태를 가지며, 다른 팀과의 협의 없이는 변경할 수 없다.

    - 기능 시스템을 자주 통합하라. 하지만 개별 팀에서 수행하는 CI빈도보다는 더 적은 빈도로 통합하라. 통합할 때는 양 팀에서 작성한 테스트를 모두 실행하라.

 

customer/supplier/ development team(고객/공급자 개발 팀)

    한 하위 시스템이 다른 시스템에 본질적으로 데이터를 공급할 때가 있다. 하류 컴포넌트는 상류 컴포넌트에 피드백을 거의 제공하지 않는 분석 작업이나 여타 다른 기능을 수행하며, 모든 의존선을 단방향으로 흐른다.

    상류 하위 시스템과 하위 시스템은 자연스럽게 두개의 bounded context로 나뉜다.

 

    두 팀 간에 명확한 고객/공급자 관계를 확립하라. 계획 회의에서 하류 팀이 상류 팀에 대한 고객 역할을 맡게 하라. 하류 요구사항에 대한 작업을 협상하고 이에 대한 예산을 책정해서 모든 이들이 일정과 약속을 이해할 수 있게 하라.

    결과로 예상되는 인터페이스를 검증하게 될 자동화된 인수 테스트를 함께 개발하라 이 테스트를 상류 팀의 테스트 스위트에 추가해서 지속적인 통합의 일부로 실행되게 하라.

 

conformist 

    sharedd kernel 밀접하게 조율하는 두 팀 간의 협력관계를 다룬다면, conformist는 협력에 관심이 없는 팀과의 통합문제를 다룬다. 독립적인 모델을 포기하는 것

 

ANTICORRUPTION LAYER (오류방지계층)

    클라이언트 고유의 도메인 모델 측면에서 기능을 제공할 수 있는 격리 계층을 만들어라. 격치 계층은 기존에 이미 존재하는 인터페이스를 거쳐 다른 시스템과 통신하므로 다른 시스템을 거의 수정하지 않아도 된다.

    해당 계층에서는 내부적으로 필요에 따라 두모델을 상대로 양방향으로 번역을 수행한다.

 

    보통 service의 집합(간혹 entitiy) 으로 표현된다. 연결 계층

 

separate ways (각자의 길)

    우리는 철저하게 요구사항들을 조사해야 한다. 두 기능 간의 관계가 필수적인 것이 아니라면 두 기능은 서로 관계를 끊을 수도 있다.

 

OPEN HOST SERVICE(공개 호스트 서비스)

    하위 시스템을 필요로 하는 곳이 많다면 좀더 유연한 접근법이 필요하다. 어떤 하위 시스템을 다른 여러  하위 시스템과 통합해야 할 경우 각 하위 시스템에 대한 번역기를 조정한다면 팀 전체가 교착 상태에 빠질수 있다.

    하위 시스템 접근과 관련된 프로토콜을 일련의 service로 정의하라. 프로토콜을 공개해서 개발 중인 시스템과 통합하고자 하는 모든 이들의 해당 프로토콜을 사용할 수 있게 하라. 새로운 통합 요구사항을 처리하게끔 프로토콜을 개선하고

    확장하되 특정한 한 팀에서 요청해 오는 독특한 요구사항은 제외하라. 그와 같은 특수한 경우에는 일회성 번역기로 프로토콜을 보강해서 공유 프로토콜을 단순하고 일관되게 유지하라.

 

PUBLISHED LANGUAGE(공표된 언어)

    두 bounded context의 모델 간에 이뤄지는 번역에는 공통의 언어가 필요하다.

    필요한 도메인 정보를 표현할 수 있는 적절히 문서화된 공유 언어를 공통의 의사소통 매개체로 사용해서 필요에 따라 해당 언어로, 또는 해당 언어로부터 번역을 수행하라

 

경계의 변형

    규모가 큰 bounded context가 선호되는 경우

        사용자의 작업 흐름이 단일화된 모델을 토대로 처리될 때 더 매끄럽게 진행된다.

        개별적인 두 모델의 매핑을 더하는 것보다 일관성 있는 하나의 모델을 이해하기가 더 쉽다.

        두 모델 간의 번역이 어려울 수 있따.

        공유 언어를 토대로 팀의 의사소통이 명확해진다.

    규모가 작은 bounded context가 선호되는 경우

        개발자 간의 의사소통에 따른 과부하가 줄어든다.

        소규모 팀과 고드 기반을 토대로 ci가 쉬워진다.

        대형 컨텍스트에는 용도가 다양한 추상화 모델을 요구할 수도 있는데, 이 경우 제공하기 힘든 기술이 필요할 때가 있따.

        각기 다른 모델은 특수한 요구사항을 해결하는 데 도움이 된다.

 

디스틸레이션

    규모가 큰 시스템에서는 격리된 도메인조차도 관리할 수 없을 정도로 복잡해질지도 모른다.

    디스틸레이션은 혼합된 요소를 분리해서 본질을 좀더 값지고 유용한 형태로 뽑아내는 과정이다.

    CORE DOMAIN의 추출!!

 

GENERIC SUBDOMAIN(일반 하위 도메인)

    모델의 일부는 전문 지식을 포착하거나 전달하지 않고 복잡성을 더하곤 한다. 부수적인 요소는 core domain을 식별하고 이해하는 일을 더욱 어렵게 만든다.

 

    현재 진행 중인 프로젝트를 위한 것이 아닌 응집력 있느 하위 도메인을 식별하라. 이러한 하위 도메인에서 일반화된 모델 요소를 추출해서 별도 module에 배치하라 

    일단 하위 도메인이 분리되고 나면 해당 하위 도메인의 계속 되는 개발에 대해서는 core domain보다 낮은 우선순위를 부여하고 그 일에 핵심 개발자를 배치하지 않는다.

 

DOMAIN VISION STATEMENT(도메인 비전 선언문)

    프로젝트 초기에는 대개 모델이 존재조차 하지 않지만 모델의 개발에 집중해야 할 필요성은 이미 거기에 있다 개발이 후반부에 이르면 모델을 심층적으로 연구하지 않아도 되는 시스템의 가치를 설명할 필요가 생긴다

    많은 프로젝트 팀에서는 관리를 위해 '비전 선언서'를 작성한다.

 

    약 한 페이지 분량으로 CORE DOMAIN을 짧게 기술하고 그것이 가져올 가치에 해당하는 가치제안을 작성하라!

 

디스틸레이션 문서

    Core domain 과 core의 구성요소 사이에서 일어나는 상호작용을 기술하는 매우 간결한 문서

    core domain의 본질적인 면면의 윤곽을 드러낸다면 디스틸레이션 문서는 모델 변경의 중요성을 나타내는 실질적인 지표로 작용한다. 모델이나 코드 변경이 디스틸레이션 문서에 영향을 주면 다른 팀원과의

    사으이가 필요하다. 

 

cohesive mechanism(응집렬 있는 메커니즘)

    개념적으로 cohesive mechanism을 별도의 경량 프레임워크로 분할하라 이제 도메인의 다른 요소들은 해법의 복잡성을 프레임워크에 위임해서 문제를 표현하는 데 집중할 수 있따.

    알고리즘을 빼서 프레임워크화 하라!

 

    메커니즘이 도메인 모델에 통합돼 있었다면 두 가지 점에서 비용이 발생했을 것이다. 모델은 추후 선택사항에 제한을 두면서 특정한 문제 해결 방법과 결합됐을 것이다.

 

segregated core(분리된 핵심)

    1. core 하위 도메인을 식별한다.

    2. 새로운 module관련 클래스를 옮긴다. 이때 module의 이름은 관련 개념에 따라 짓는다.

    3. 개념을 직접적으로 표현하지 않는 서버 데이터와 기능으로 코드를 리팩터링한다. core 하위 도메인의 불순물을 제거하고 그곳에서 다른 패키지를 참조하는 바를 명시적이로 그 자체로도 이해할 수 있는 상태로 만든다.

    4. 새로생긴 module의 관계와 상호작용을 더욱 단순하고 전달력 있게 만든다.

 

abstract core(추상화된 핵심)

    별도 module의 하위 도메인 간에 상호작용이 활발한 경우 module 간에 참조가 많이 만들어져야 해서 분할의 가치가 상당수 사라지거나, 또는 상호작용이 간접적으로 일어나야 해서모델이 불분명해진다.

 

    모델의 가장 근본적인 개념을 식별해서 그것을 별도의 클래스나 추상 클래스, 또는 별도 인터페이스로 수정하라 이 추상 모델이 중요 컴포넌트 간에 발생하는 상호작용을 대부분 표현할 수 있게끔 설계하라.


대규모 구조
    책임 계층 을 나누어라
    각 객별 객체에 손수 만든 책임이 할달돼 있다면 가이드라인드 없고, 균일함도 없고, 넓은 범위에 걸친 도메인을 동시에 다룰 능력도 없는 셈이다.
    큰 모델에 응집력을 부여하려면 그러한 책임할당에 특정 구조를 도입하는 것이 도움이 된다.
    ex) 의사결정지원, 정책,운영,잠재기능 등


평가
    1. context map을 그려라 일관된 context map 을 그릴 수 있는가? 그렇지 않다면 모호한 상황이 있는가?
    2. 프로젝트상의 언어를 쓰는 데 힘써라. 유비쿼터스 언어가 있는거 유비쿼터서은어가 개발에 도움을 줄 만큼 풍부한가?
    3. 무성이 중요한지 이해하라 core domain을 식별했는가? domain vision statement가 있는가? domain vision statement를 작성할수있는가?
    4. 프로젝트 사용하는 기술이 DDD에 유리한가 불리한가
    

1. 변수, 함수, 이름을 분명하게 짓기

2. 함수는 최대한 작게 하나의 기능만 담당(들여쓰기 수준은 1단이나 2단을 넘어서지 않도록 한다.)
   - 함수당 추상화 수준은 하나로!
   - 내려가기 규칙(추상화가 높은순 부터 낮은순 대로)
   - 서술적인 이름 사용
   - 모듈 내에서 함수 이름은 같은 문구 명사 동사 ex(inclusePages,setPages..)
   - 인수(매개변수) 3개는 가능한 피하고 4개이상은 이유가 필요하지만, 이유가 있어도 사용하면 안된다.
   - 플래그 인수는 안좋다. 이미 그걸 인수로 준 것 자체가 함수가 두 역할을 한다는 것 이기 떄문
   - 오류 코드보다 예외를 사용하라!
   - try/catch 블록 뽑아내기 (함수로 따로 분리 해 내기)

3.주석을 가능한 줄이도록 꾸준히 노력해야 한다.
    - 코드로 의도를 표현하라(많은 경우데 주석을 함수로 만들어 표현해도 충분하다.)
    - 좋은 주석
        - 법적인 주석(저작권 정보, 소유권 정보) ex) 첫머리 
        - 정보를 제공하는 주석 
        - 의도를 설명하는 주석  //스레드를 대량 생성하는 방법으로 어떻게든 경쟁 조건을 만들려 시도한다.
        - 의미를 명료하게 밝히는 주석// a==a a!=b .....
        - 결과를 경고하는 주석 // 여유시간이 충분하지 않다면 실행하지 마십시오.
        - TODO 주석 '앞으로 할일' 프로그래머가필요하다 여기지만 당장 구현하기 어려운 업무를 기술
        - 중요성을 강조하는 주석
        - 공개 API를 구현한다면 Javadocs를 작성하라!

종속함수 한 함수가 다른 함수를 호출한다면 두 함수는 세로로 가까이 배친한다. 또한 가능 하다면 호출하는 함수를 호출되는 함수보다 먼저 배치한다.
    - 호출되는 함수를 호출하는 함수보다 나중에 배치한다. 그러면 소스 코드 모듈이 고차원에서 저차원으로 자연스럽게 내려간다.

개념적 유사성 개념적은 친화도가 높을수록 코드를 가까이 배치한다. ex)함수에서 다른 함수호출 , 비슷한 기능을 하는 함수들 

4. 객체 
    자료의 추상화 
        객체는 추상화 뒤로 자료를 숨긴 채 자료를 다루는 함수만 공개한다.
        자료구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다.

5. 오류 코드보다 예외를 사용하라
    - 오류 함수 사용 (분리)
    - try catch finally 문부터 작성하라
    - 미확인(unchecked) 예뢰를 사용하라
        - checked 예외 는 컴파일 단계에서 확인되며 반드시 처리해야 하는 예외입니다.
            IOException
            SQLException
        - Unchecked 예외 는 실행 단계에서 확인되며 명시적인 처리를 강제하지는 않는 예외입니다.
            NullPointerException
            IllegalArgumentException
            IndexOutOfBoundException
            SystemException
            단점 : 해당 함수 뿐만아니라 호출하는 함수도 수정을 해줘야 하기 때문에 OCP를 위반하게된다
        
        - 예외에 의미를 제공하라 (예외를 던질 때는 전후 상황을 충분히 덧붙인다. 오류 메시지에 정보를 담아 예외와 함께 던진다)
    - 감싸기 클래스 작성
    - 정상 흐름을 정의하라.
       외부 API를 감싸 독자적인 예외를 던지고, 코드 위에 처리기를 정의해 중단된 계산을 처리한다. 때로는 중단이 적합하지 않은 때도 있다.
       예외가 발생한다면 기본 값 객체를 만들어서 반환한다. 이를 특수 사례 패턴이라고 한다 그러면 따로 예외적인 상활을 처리할 필요가 없다.
    - null을 반환하지 마라!
        예외를 던지거나 특수 사례 객체를 던져라!!
    - null을 전달하지 마라!!

6.경계
    외부 코드를 우리 코드에 깔끔하게 처리 하는 기법과 기교

7. TDD 법칙
    F.I.R.S.T.
        빠르게(테스트는 빨리 돌아야한다.), 독립적으로(각 테스트 서로 의존 x), 반복가능하게(어느 환경에서라도 테스트가 돌아야한다.), 자가 검증하는(테스트는 성공 아니면 실패로 결과를 알수 있어야한다.),
        적시에(테스트는 적시에 작성해야 한다. 단위테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.)

    첫번쨰 법칙 : 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
    두번째 법칙 : 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
    세번째 법칙 : 현재 실패하는 테스트를 통과할 정도로만 실제 코도를 작성한다.

    테스트는 유연성, 유지보수성, 재사용성을 제공한다. (테스트 케이스가 있다면 변경이 쉬워진다)
    
    깨끗한 테스트 코드를 만들려면 가독성이 좋아야 한다.
    명확한 분류 (ex 세가지 부분으로 나뉜다 1. 테스트 자료를 만든다. 2. 테스트 자료를 조작한다 3. 조작한 결과가 올바른지 확인한다.)
    
    테스트 당 assert 하나 보다는 --> 테스트 당 개념 하나!!
        - 저자: 훌륭한 지침이라고 생각한다 하지만 떄로는 함수 하나에 여러 assert 문을 넣기도 한다. 단지 assert문 개수는 최대한 줄여야 좋다는 생각

8. 클래스
    - 클래스는 작아야한다!
    - 캡슐화
        변수와 유틸리티 함수는 가능한 공개하지 않는 편이 낫다 하지만 반드시 숨겨야 한다는 법칙도 없다.(테스트 코드를 위해 protected로 선언)
        하지만 캡슐화를 풀어주는 결정은 언제나 최후의 수단
9. 시스템
    시스템 제작과 시스템 사용을 분리하라
        - 소프트웨어 시스템은 (애플리케이션 객체를 제작하고 의존성을 서로 '연결'하는) 준비 과정과 (준비과정 이우헤 이어지는) 런타임 로직을 분리하여야 한다.

'Java' 카테고리의 다른 글

java Beans  (0) 2019.05.22
getTextField null 처리  (0) 2019.05.06
프로그래밍 언어란? (java란?)  (0) 2019.02.27

샤딩
    각각의 데이터가 어떤 서버에 들어있는지를 저장하고 알려주는 역할이 필요하다.
    이처럼 샤딩을 하고 난 이후의 역할이 분배된 구성 요소들을 하나로 묶어 '샤드 클러스트'라고 한다.

    샤드 
        애플리케이션이 사용할 데이터를 나눠서 저장하고 있다.

    설정서버
        애플리케이션 데이터를 제외하고 샤드 클러스터가 작동하기 위해 필요한 모든 정보를 저장한다. 이런 정보를 메타데이터라고한다.

    라우터
        샤드와 설정 서버가 특정 정보를 저장하는 역할을 했다면 라우터는 직접적으로 드라이버의 명령을 받아서 어떤 작업을 수행할지 판단하고 결과물을 가져다 드라이버에 넘겨주는 역할을 한다.
    
    mongod 프로세스와 mongos 프로세스가 서로 통신 그 후 -> 샤드에 데이터 저장

샤드키
    샤드 클러스터에서 정보를 어떻게 나누어 저장하느지에 따라서 성능상의 문제가 발생할 수 있다. 예를들어 자주 사용하는 정보가 한쪽 샤드에 몰리는 상황을 생각해보자
    이런 경우, 대부분의 샤드는 쉬고 있는데도 서비스 속도가 저하되는 상황이 발생한다. 
    따라서 정보를 나누는 기준을 잘 설정해야한다. 기준이 되는 값이 샤드키이다.

프라이머리 샤드는   
    각각의 데이터베이스에 샤딩을 허용할수있다. 샤딩을 적용받은 데이터베이스는 프라이머리 샤드를 필수적으로 사져야 한다,
    데이터베이스 내에서 컬렉션을 저장하는 기본샤드다.


수직적 샤드
    1번샤드                                             2번샤드
    {A데이터베이스 컬렉션} {A데이터베이스 컬렉션}       {B데이터베이스 컬렉션} {B데이터베이스 컬렉션}

수평적 샤드
    1번 샤드                        2번 샤드            3번 샤드
    {가 컬렉션} {나 컬렉션의 1/3}   {나 컬렉션의 1/3}   {다 컬렉션의 1/3}
    나 컬렉션이 크기가 클 경우

청크
    샤드 사이에 분할된 정보를 효과적으로 관리하기 위해 '청크'를 사용한다. 샤드키값을 기준으로 한 도큐먼트의 묶음 이다 (각각의 청크는 샤드키를 기준으로 상한값과 하한값을 갖는다.
밸런서
    어떤 청크가 64mb를 넘어버리면, 둘로 쪼개지면서 크기가 반으로 줄어든다. 또한, 한쪽 샤드에 청크가 몰릴경우 샤드 클러스터의 밸런스가 샤드사이의 청크를 교환해준다
    
    sh.stopbalancer()
    도큐먼트가 대량으로 입력되거나 삭제되어서 밸런싱을 머추어야하는 상황
    샤드를 추가하거나 데이터를 복구할 때 쓰면 좋다.


범위 샤딩
샤드키 설정 원칙
    값의 종류가 다양해야한다 이유는 청크 분리 불가능 예시 성별,카테고리,대분류
    값이 골고루 분포해야한다       청크 분리 불가능,특정 샤드 작업 편중 예시 성씨,신장,체중
    값이 지속적으로 증가/감소되지 않아야 한다        특정 샤드 작업 편중 예시 신장,재고,수정날짜
해시 샤딩
    값의 종류가 다양해야 한다.
    값이 골고루 분포해야한다.
    값이 지속적으로 증가. 감소되지 않아야 한다.

샤딩 구역 설정
    샤드 클러스터에 범위 샤딩 혹인 해시샤딩을 구성하고 나서 '샤딩 구역' 을 설정할 수있다. 
    ex 샤드키 '1'           샤드키 '2'
       구역{KR}             구역{US}

    sh.addShardTag("샤드 이름","태그 이름")
    sh.addShardTagRange(
        "<데이터베이스>.<컬렉션>",
        {<샤드키>:<최솟값>},
        {<샤드키>:<최대값>},
        <태그 이름>
        )

    최솟값으 가지지 않으면 MinKey를 최댃값을 가지지 않으면 MaxKey로 범위를 설정하면 된다.

    샤딩구역이 필요한 경우
        - 샤드 성능이 다른 경우
        - 특정 정보를 일부 샤드에 나누어 저장해야 하는 경우
        - 지역별로 읽기 쓰기가 빈번한 경우

실습
    /db/data/config0-0
    /db/data/config0-1
    /db/data/config0-2
    설정 서버 구성

    mkdir -p /db/data/config0-0/rs0-0 /db/data/config0-0/rs0-1 /db/data/config0-0/rs0-2

    실행
        mongod --configsvr --replSet config0 --port 27018 --bind_ip localhost --dbpath /db/data/config0-0
    
    mongo --port 27018

    rs.initiate({
        _id:"config0",
        configsvr:ture,
        members: [
            {_id:0,host:"localhost:27018"},
            {_id:0,host:"localhost:27019"},
            {_id:0,host:"localhost:27020"}
        ]


    })

    샤드 구성

    /db/data/shard0-0
    /db/data/shard0-1
    /db/data/shard0-2
    설정 서버 구성

    mkdir -p /db/data/shard-0/rs0-0 /db/data/shard0-0/rs0-1 /db/data/shard0-0/rs0-2

    실행
        mongod --shardsvr --replSet shard0 --port 27021 --bind_ip localhost --dbpath /db/data/shard0-0
    
    mongo --port 27021

    rs.initiate({
        _id:"shard0",
        configsvr:ture,
        members: [
            {_id:0,host:"localhost:27021"},
            {_id:0,host:"localhost:27022"},
            {_id:0,host:"localhost:27023",arbiterOnly:true}
        ]


    })

    몽구스 설정하기 샤드클러스트를 이용하기 위해서 필요한 인스턴스이다.

    mongos --configdb config0/localhost:27018 --port 20000

    mongo --port 20000 

    sh.addShard("shard0/localhost:27021")

    user config
    db.shards.find() 결과를 확인 할 수 있다.

    mongo --port 20000
    show dbs
    car_accident

    use car_accident

    show collections

    sh.enableSharding("car_accident") -> 데이터베이스에 샤딩을 활성화

    범위 샤딩 구성하기
    db.by_month.createIndex({country:1})
    sh.shardCollection("car_accident.by_month",{
        country:1
    })

    헤시 샤딩 구성하기
    db.area.createIndex({country:"hashed"})
    sh.shardCollection("car_accident.area",{
        country:"hashed"
    })

    mongod 설정 파일 사용
    /etc/mongod.conf

    설정 사진들..

    샤드 클러스터 관리하기

    설정 서버 
    
    use config 
    show collections 

    여러 컬렉션들이 나옴 필요하면 찾아보기 

    use config
    db.status.find()
    //shards 조회

    sh.status() 
    //클러스터 상태 확인하기
    
사용자 인증
    security:
        authorization: enabled

복제
    가장 큰 목적 : 서비스 중인 mongodb 인스턴스에 문제가 생겼을 때, 정보가 복제된 다른 인스턴스를 이용해서 문제가 생긴 인스턴스를 대체하는 것이다.
    
    하지만, 복제된 인스턴스는 변경된 정보를 동기화하는데 시간이 걸린다.

    복제를 수행 하기 위해서는 여러 mongod 인스턴스가 모인 "묶음"이 필요하다. 이 묶음에 속하게 되면 서로의 정보를 동기화한다. 이런 묶음을 복제세트라고하고 이에는 3가지로 구성된다.
    1. 클라이언트와 읽기 및 쓰기 작업을 하는 '프라이머리 구성원' 
    2. 프라이머리 구성원의 정보를 동기화하는 '세컨더리 구성원'
    3. 정보를 저장하지는 않고 복제 세트의 복구를 돕는 '아비터 구성원' 이렇게 세 가지 종류의 구성원이 복제 세트를 구성한다.

    서로 살아 있는지 10초마다 핑을 보내는 작업을 수행한다. 이를 하트비트라고한다.

    복제 세트 구성원의 기능

                프라이머리                  세컨더리                아비터

    주요역할    클라이언트와 정보교환       프라이머리 정보 복제        투표진행
    정보저장            O                           O                   X
    선거에서역할    문제가 발생              피선거권,선거권 보유      선거권 보유


    새컨더리가 프라이머리가 되고 프라미어리보다 최신의 정보는 지운다. 그래서 롤백이 되는데 소실되어서는 안되는 민감한 정보를 저장해야 하는 경우에는 WriteConcern을 보수적으로 설정해야한다.

    mongod
        --replSet <복제 세트 이름>
        --port <포트번호>
        --bind_ip <연결할아이피>
        --dbpath <정보를 저장할 경로>
        --oplogSize <오피로그 크기>
    
    mkdir -p /db/data/rs-0 /db/data/rs-1 /db/data/rs-2
    
    포트 27018, 27019, 27020

    mongo --port 27018 실행 
    
    //rs()이라는 이름의 복제 세트로 묶는다
    rs.initiate({
        _id:"rs0",
        members:[
            {_id:0,host:"localhost:27018"},
            {_id:0,host:"localhost:27019"},
            {_id:0,host:"localhost:27020"},
        ]

    })

    rs.status() // 상세 정보
    프라이머리에서 데이터 넣고, 세컨더리에서 조회
    rs.slaveOk() //세컨더리는 기본값으로 셸을 사용하지 못하게 되어있다. 사용가능하게 하기

    
    배포 환경에 복제 세트 구성
        mongod.conf 파일을 수정해서 인스턴스의 기본 값이 외부와 연결이 가능하도록 설정해야 한다.
        /etc/mongod.conf 결로에 설정파일 존재

        net:
            bindIp: 127.0.0.1
            port: 27017

    복제 세트 세부 설정
        rs.conf()
        rs.reconfig(<복제옵션>) // 세컨더리의 우선순위 변경 가능

    새로운 구성원을 복제 세트에 추가하려고 할때 add 명령어를 이용하면 추가 할 수 있다.
    rs.add({
    {_id:,
    host:,
    설정값들..
    }
    })
    
    rs.remove("128.20.1.33") //복제 세트에서 제외 하고자 할 떄에는 해당 구성원의 인스턴스를 종류하고, remove 명령어를 주어서 구성원을 제외하면 된다.


    읽기 선호 설정이 가능하다 
        기본은 프라이머리에서 읽어오지만, 읽기 작업을 분산시킬수 있다. ( 드라이버에서 관리, 식제 개발할 떄에는 드라이버의 설정에 맞추어 개발해야 한다.)
    
    1.프라이머리 구성원에서 읽는 상태
    2.프라이머리 구성원에서 우선적으로 읽는 상태(읽기 작업이 밀리게 되면 세컨더리로부터 정보를 불러오기 때문에 변경사항 반영이 좀 늦을수 있다.)
    3.세컨더리 구성원에서 읽는 상태
    4.세컨더리 구성원에서 우선적으로 읽는 상태
    5.가까운 구성원에서 읽는 상태 ( 정보 변경 반영이 클라이언트마다 제각각이 될 우려가 있다.)


동기화 작동 방식
    오피로그 
        Mongodb 인스턴스 내에서 변경된 정보 내역을 저장한 특별한 Capped 컬렉션이다.
        db.oplog.rs.find().limit(1).pretty() // 조회
        
        //사진
    초기 동기화
        새로운 세컨더리를 추가했을 때 오피로그의 정보만으로 동기화를 수행할 수 없다면 '초기 동기화'를 수행하게 된다.

    ReadConcern 
        그냥 프라이머리에 기록된 정보를 가져올지, 아니면 대다수의 복제 세트에 기록된 정보를 가져올지 정할 수있다.
        local 단계 majority(여러 개의 도큐먼트를 작업하는 트랜잭션에 이 옵션을 사용하려면) 단계 linearizable 단계 (시간옵션을 설정 해주어야함)

        cursor.readConcern("linearizable").maxTimeMS(10000)
        //쿼리의 결과로 나온 커서 뒤에 readConcern이라는 명령어를 이용하면 읽어오는 정보에 관련 옵션을 붙일수있다.

        db.rating.aggregate(
            [{$match:{rating:{$lt:5}},
            readConcern:{level:"majority"}          
            }]
        )

        session =db.getMongo().startSession()
        session.startTransaction({readConcern:{lecel:"snapshot"}},
        WriteConcern:{w:"majority"}});
        session.commitTransaction();
        session.endSession();

    WriteConcern
        복제 세트에 장애가 발생했을 때 중요한 정보가 사라질지, 유지될지 결정할 수 있다.
        w : 복제 세트의 어느정도의 구성원에 쓰기 작업이 완료되어야 전체 쓰기 작업이 완료되었다고 판단할지 결정하는 옵션
        j : 쓰기 작업은 메모리에 변경 사항을 남겼다가 일정 주기로 디스크에 변경 사항을 기록 디스크 변경사항을 임시로 저장하는 작업을 저널링이라고 한다. 저널링은 장애가 발생해도 기록이 남기 때문에 복구가 가능하다.
        wtimeout : w 옵션에서 설정한 구성원들을 기다릴 수 있는 최대시간 , 시간이 지나면 에러 반환 이미 실행한 쓰기 작업 자체는 취소되지 않는다.

        db.rating.aggregate(
            [ {$match:{rating:{$lt:5}}}],{
                writeConcern:{w:"majority",j:t}
            }
        )

        ession =db.getMongo().startSession()
        session.startTransaction({readConcern:{lecel:"snapshot"}},
        WriteConcern:{w:"majority"}});
        session.commitTransaction();
        session.endSession();

    오피로그의 크기
        세컨더리가 동기화를 끝내지 못했는데 오피로그의 크기가 작아 동기화할 데이터가 지워진다면 가지고 있는 데이터를 모두 지우고 초기 동기화 과정을 가지게 된다.
        다행히 4.0 버전 이상부터는 대다수의 세컨더리에서 오피로그를 동기화하지 못했으면 프라이머리의 오피로그를 삭제하지 않는 기술이 탑재 되었다

        - 세컨더리를 잠깐 복제 세트에서 제외 했다가 다시 포함시키는 상황
        - 물리적으로 백업된 정보를 인스턴스에 덮어씌우고 세컨더리를 복제 세트에 추가하는 상황

        오피로그 크기 수정하기
        use local
        db.oplog.rs.stats().maxSize

        db.adminCommand({replSetResizeOplog:ture,size:16834})

    동기화 상태 확인
    rs.printSlaveReplicationInfo()

1. 스키마가 자주 바뀌는 환경
ex) 
1.애자일 개발 방법론이나 나선형 모델의 시제품을 만들 때와 같이 최종적인 개발 명세가 확정되지 않는 상황
2.로깅을 하기 위한 용도로 사용할 수도 있다. 다양한 형식의 로그를 기록할 때에도 매우 유용하다.
2. 분산 컴퓨팅 환경
샤딩과 복제를 DBMS 수준에서 지원해서 여러 관련 기능들을 보다 효과적으로 적용할 수 있다.
-복제는 '고가용성' 환경이 필요할때 고려해볼만하다. (항상 사용할 수 있는 상태)
-샤딩은 저장용량이 늘어나면서 읽기,쓰기 속도가 필요한 만큼 나오지 않을 때 적용할 수 있다.

* 리눅스에서 mongodb설치시 권한 설정 (sudo chmod -R go+w /data/db


도큐먼트는 BSON 구조는 값으로 매우 다양한 데이터 타입을 가진다.

db.dropDatabase() 
db.collection.drop()
db.collection.renameCollection(바꿀이름)

Capped 컬렉션
정해진 크기를 초과하게 되면, 자동으로 가장 오래된 데이터를 삭제하게된다
db.createCollection(<컬렉션이름>,{capped:true, size:<제한할 크기>)
capped 컬렉션은 로그 데이터나, 일정 시간 동안만 보관하는 통계 데이터를 보관하고 싶을 때 유용하게 사용 할 수 있다.


집계 파이프라인 문법 사용


WriteConcern
mongodb는 기본적으로 메모리메 미리 저장한 후, 천천히장기 저장장치로 데이터를 옮긴다. 따라서 데이터베이스에 갑저가 문제(정전 등)이 생기면 메모리에만 담겨 있어
데이터가 손실 된다.


db.user.insertMany({다큐먼트1},{다큐먼트2} ....)
여러 다큐먼트를 한번에 넣기

 

find 
    - 쿼리 
        db.containerBox.find({name:"가위"})
    - 점연산자 
        - {name:{firstName:"Karoid",lastName:"Jeong"}}
          db.A.find({"name.firstName"::Karoid"})
        - {numbers: [101,32,21,11]}
          db.A.find({"numbers.0":52)
    - 프로젝션
        - 어떤 도큐먼트를 불러올지를 결정하는 파라미터
        db.containerBox.find(null,{name:true})
        db.containerBox.find(null,{name:1})

        null => {name:'가위'}  조건 찾기
    - cursor 커서 
        모든 정보를 직접 반환하지 않고 커서를 반환한다.
        toArray()를 메소드를 사용하면 커서로부터 정보를 전부 가져올 수 있다.
            - 만약 find문의 모든 값이 다 필요하지 않다면 toArray 메소드는 비효율적이다.
            - 또, 필요한 도큐먼트의 총 크기가 매우 크다면 toArray 메소드를 사용 할 시 메모리 용량을 초과 할수도있다.

수정
    replaceOne (대체)
    기존의 값 유지 되지않고, 교체되어 버린다.
    - db.user.replaceOne({username:"karoid"},{
        username:"Karpoid",
        status:"Sleep",
        points:100,
        password:2222
    },(upsert:true))

        - upsert 
            참/거짓 값을 설정할 수 있다, 참값으로 설정된 경우 쿼리로 찾은 도큐먼트가 없다면, 찾은 내용으로 도큐먼트를 생성해서 수정하게 된다. 
    
    updateOne, updateMany (수정)
        -db.containerBox.updateMany({name:"bear"},{$set:{name:"teddy bear",category:"toy"}})
            ($unset 도큐먼트상의 field 필드를 제거한다.)

수정 배열 연산자
    db.character.insertMany([
        {name:'x',inventory:['pen','cloth','pen']},
        {name:'y',inventory:['book','cloth'],position:{x:1,y:5}},
        {name:'z',inventory:['wood','pen'],position:{x:0,y:9}}
    ])

    db.character.updateMany({},{
        $set:{"inventory.$[penElem]":"pencil"},
        {arrayFilters:[{penElem:'pen'}]}
    })

    $set:{"inventory.$[]":"pencil"} -> 배열에 pen 요소가 두개 있어도 모두 pencil로 바뀌게 된다.

삭제는 수정과 매우 유사하다

트랜잭션 명령어
    session = db.getMongo()startSesstion()
    session().startTransaction({readConcern :{level:"snapshot"},
    writeConcern:{w:"majority"}});
    
    <원하는 작업을 수행>
    session.commitTransaction();
    session.endSession();    
    <문제가 생길 경우 중간에 작업을 취소>
    session.abortTransaction();


$text 연산자
    MongoDB의 $text 연산자는 해당 컬렉션의 텍스트 인덱스 안에서만 작동하기 때문에, 문자열 인덱스를 생성해야 한다.
    
    db.stores.insertMany([
        {_id:1, name :"java Hut",description:"Coffee and cakes"},
        {_id:2, name :"asdf",description:"Coffee and cakes"},
        {_id:3, name :"xcxc",description:"Coffee and cakes"},
        {_id:4, name :"hhh",description:"Coffee and cakes"},
        {_id:5, name :"jjj",description:"Coffee and cakes"},
        {_id:6, name :"jkkt",description:"Coffee and cakes"},
        {_id:7, name :"ccc",description:"Coffee and cakes"},
    ])

    db.stores.createIndex({name:"text",description:"text"}) - 문자열 인덱스를 생성
    db.stores.find({$text:{$search:"bake coffee cake"}})

    - 대소문자를 구분하지 않고 검색을 한다.

    db.stores.find({$text:{$search:"\"coffee shop\""}})
    여러 단어를 띄어쓰기와 함께 사용하게 되면 해당 단어들 중 일부만 포함된 도큐먼트라도 불러오게 된다.

    db.stores.find({$text :{$search:"shopped"}})
    shop이라는 단어의 진행형인 shopping이 포함된 도큐먼트를 불러온다

배열 연산자
    db.inventory.find({tags:{$elemMatch:{$gt:10,%lt:5}}})
    하나라도 두 조건을 동시에 만족하는 값을 가져옴

    db.inventory.find({tags:{$all:["red","blank"]}})
    순서와 상관없이 모든 요소를 가지는 값을 가져옴

    db.inventory.find({"tags":{size:3},....})
    배열의 해당 크기와 같은 도큐먼트를 찾는다

프로젝션 연산자
    프로젝션에서는 점연산자가 첫번째 배열을 가르키지 않는다.
    
    $slice등을 사용
        db.inventory.find({},tags:{$slice:1}})
        tags 필드의 첫 번째 요소만 출력 된다.

        마지막 요소로부터 n개를 출력하고 싶다면 연산자의 값으로 -n을 설정하면 된다.
        {$slice:[1,2]}

    elemMatch
        배열 속에서 특정 조건을 만족하는 요소만 노출

    $연산자 
        tags 필드의 값 중 "red"를 갖는 도큐먼트를 찾는경우
        db.inventory.find({tags:"red"},{"tags.$":true})



집계 명령어
    집계 방법론과 효율성
         도큐먼트를 집계하는 방법은 크게 세 가지가 있다.
         1. 데이터베이스의 모든 정보를 불러와 애플리케이션 단게에서 집계하는 방법
         2. MongoDB의 맵-리듀스 기능을 이용하는 방법
         3. MongoDB의 집계 파이프라인 기능을 이용하는 방법 

         집계 파이프라인은 MongoDB 내부에서 작동, 다른 방법들은 정보교환을 위해 메모리가 필요하게 된다.
         집계 파이프라인 방식으로 원하는 결과를 얻지 못할 수도 있다.
         그럴 경우, 맵-리듀스 방식을 사용하면 된다.

        - 맵-리듀스의 작동 방식 1
        
        Rating
        {_id:1,rating:1,user_id:2}        -->       {1:2}           -->     {_id:1,value:2}
        {_id:1,rating:1,user_id:2}        map       {2:3}           -->     {_id:2,value:3}
                                                    {3:[4,1]}       -->     {_id:3,value:2}
                                                    {4:[5,8]}       -->     {_id:4,value:2}
        
        db.rating.mapReduce(mapper, reducer, {out:{inline:1}})

        - 맵-리듀스의 작동 방식 2
        
        Rating                                                     reduce           중간 결과물
        {_id:1,rating:1,user_id:2}        -->       {1:2}           -->       ----- {_id:1,value:2}
        {_id:1,rating:1,user_id:2}        map       {2:3}           -->       |     {_id:2,value:3}
                                                                              | 
                                          -->       {3:[4,1]}       -->       V     {_id:3,value:2}
                                                    {4:[5,8]}       -->     --->    {_id:4,value:2}  최종결과물
                                                                           reduce 

        - 파이프라인 방식
        $project (어떤 필드를 만들고 어떤 필드를 숨길지 설정)
            db.rating.aggregate([
                {
                    $project:{_id:0,rating:1,hello:"new field"}
                }
            ])
            {"rating":1,"hello":"new field"}    

            db.rating.aggregate([
                {
                    $project:{_id:0,multiply:{
                        $multiply:[$_id","user_id"]
                    }}
                }
            ])
            {"multiply":2} 

        $group(그룹화이다.)
            db.rating.aggregate([
                {
                    $group:{_id:"$rating",count:{$sum:1}}
                }
            ])

        $match(도큐먼트를 필터링해서 반환한다. find문과 비슷한 역할이다.)
            db.rating.aggregate([
                {
                    $match:{rating:{$gte:4}}
                },
                {
                    $group:{_id:"$rating",user_ids:{$push:"$user_id"}}
                }
            ])

            {"_id" :5 ,"user_ids:[11,12,10,9]}

            평점이 4 이상인 사용자의 id들을 배열의 형태로 정리

             db.rating.aggregate([
                {
                    $match:{rating:{$gte:4}}
                },
                {
                    $group:{_id:"$rating",user_ids:{$push:"$user_id"}}
                },
                {
                $unwind:"$user_ids"
                }
            ])

            {"_id" :5 ,"user_ids:9}
            {"_id" :5 ,"user_ids:10}
            {"_id" :5 ,"user_ids:11}

        $out(도큐먼트를 저장)
            
             db.rating.aggregate([
                {
                    $match:{rating:{$gte:4}}
                },
                {
                    $group:{_id:"$rating",user_ids:{$push:"$user_id"}}
                },
                {
                $unwind:"$user_ids"
                },
                {
                $out:"user_ids_by_rating"    
                }
            ])

        $limit(입력 도큐먼트 중 지정된 숫자만큼만 출력)
        $skip(입력 도큐먼트 중 지정된 숫자만큼 건너뛰고 출력)
        $sort(도큐먼스틑 정렬 1이면 오름차순,-1이면 내림차순)
        
뷰 생성하고 삭제하기
    db.createView(<뷰 이름>,<출처 컬렉션>,<파이프라인 스테이지 배열>,)
    프로젝트 연산자 전부 사용하지 못하고, 사용할 수있는 명령어가 제한적이다.

데이터 모델링과 인덱싱
    - 레퍼런스 방식
        정보의 양이 늘어날수록 크기가 작은 도큐먼트의 개수가 늘어나게 된다.
        도큐먼트의 크기는 작고, 정보를 추가하려면 도큐먼트를 추가한다.
        연결된 정보를 모두 불러오는데 더 오래 걸린다.
        연결된 정보를 일부만 불러올 때 더 빠르다.

    - 임베디드 방식
        도큐먼트의 크기가 무한히 커질 수도 있다.
        도큐먼트의 크기는 크고, 정보를 추가하려면 도큐먼트를 수정한다.
        임베디드 되어 있는 정보를 더 빨리 불러 올 수 있다.
        도큐먼트 전체를 읽어야 해서 느리다.
        장점 
            기본적인 도큐먼트 생성 및 삭제 작업은 하나의 도큐먼트에 대해 원자성이 지켜진다. (하지만 최근 mongodb가 트랜잭션을 지원하면서 크게 장점이 되지 않는다. 다수의 도큐먼트도 원자성을 보존할 수 있기 때문)
            거의 대부분의 글을 노출시켜야 한다면 레퍼런스 방식이 좋은 성능
            하나의 서버에서는 읽는 다면 속도차이가 별로 나지 않지만 여러대의 서버로 샤딩 되어 있다면 속도 차이가 날 수 밖에 없다.


    결론                주로 읽기 작업 위주                         주로 쓰기 작업 위주
    도큐먼트가 크다     임베디드 된 정보를 대부분 불러올때 유리         불리하다.
    도큐먼트가 작다     임베디드 된 정보를 자주 불러와야 하면 유리      조금 불리하다.


다중키 인덱스

    배열 값에 대한 검색 상황을 대비에 '배열에 대한 인덱스'를 지원
텍스트 인덱스

    $text 연산자를 사용하기 위해서 생성 되어야 하는 인덱스가 바로 텍스트 인덱스, 영어의 경우 단어의 원형으로 인덱스를 생성 한국어는 형태소별 지원이 되지 않음
해시 인덱스
    핵시인덱스를 포함한 복합인덱스 생성불가, 배열을 값으로 가지는 필드에 설정 불가
    주로 해시샤딩으로 사용하는 것이 일반적

인덱스 명령어
    단일키 인덱스
        db.movie.createIndex(
        {평점:1 },)
    복학키 인덱스
        db.movie.createIndex(
            {평점:1,점수:-1},
        )
    다중키 인덱스 (임베디드 도큐먼트)
        db.movie.createIndex(
            {"리뷰.제목":1},
        )
    텍스트 인덱스가
        db.movie.createIndex(
            {제목:"text"},
        )
    해시 인덱스
        db.movie.createIndex(
            {배급시 :"hashed"},
        )

    {name:"배급사 해시 인덱스"} -> 인덱스 이름 설정가능

    TTL 인덱스
        일정 시간이 지나면 자동으로 도큐먼트를 삭제하도록 만들어줌
    
    고유 인덱스 (같은 값이 저장되는 것을 방지할 수있게 도와준다.)
        {unique: true}

    인덱스 조회 및 삭제 명령
    db.collection.getIndexes() 컬렉션의 모든 인덱스를 보여준다
    db.collection.dropIndex(인덱스 설정 혹은 이름) 인덱스 삭제
    db.collection.dropIndexs() 모든 인덱스 삭제


    find.explain() 어떤 과정을 거쳐서 쿼리가 진행되었는지 확인 가능하다.
    만약 인덱스가 사용되었다면 IXSCAN 스테이지가 포홤된 쿼리 계획이 나타나야 한다.

    (*파이프라인에서는 db.rating.explain().aggregate)

    모든 쿼리를 explain으로 확인 할수 없으니 프로파일러를 통하여 확인가능
    db.setProfilingLevel(2)
    db.setProfilingLevel(1,50) 50ms 이상인 작업은 모두 기록하게 된다.

    현재 실행되고 있는 잠금필드
    db.currentOp()
    

혁신이란 늘 한 발 먼저 움직이고 빠르게 행동 할 때 가능하다.

기술 ( 구현 가능성) 사업(시장성) 인간적 가치(사용성,적합성)

혁신을 원한다면 이 세가지의 균형이 중요하다.

만드는 역량보다 더 중요한 것은 만들대상이다. 사람들이 필요로 하는 부분을 만들 때 지속가능성 역시 생길 수 있다.

1. 사무실에서 알 수 있는 것은 없으니 현장으로 나가라.
2. 고객 개발에 애자일 개발을 접목하라.
3. 실패는 탐색 절차의 필수적인 요소이다.
4. 끊임없이 반복하고 전환하라.
5. 고객과 만나는 순간 어떤 사업 계획도 무의미하므로 비즈니스 모델 캔버스를 활용하라.
6. 가설을 검증하고자 실험과 테스트를 설계하라.
7. 시장 유형에 맞춰라, 시장 유형에 따라 모든 게 바뀐다.
8. 스타트업은 기존 기업과 다른 지표를 쓴다.
9. 빠른 의사 결정, 순환 주기, 속도, 박자를 중시한다.
10. 열정이 가장 중요하다.
11. 스타트업의 직책은 대기업의 직책과 다르다.
12. 필요할 때만 쓰고 아껴라.
13. 배운 것을 소통하고 공유하라.
14. 성공적인 고객 개발은 합의에서 시작한다.


경계된 컨텍스트 : 하나 이상의 경계된 컨텍스트를 포함하는 마이크로서비스를 만들지 말아야 한다.
전체 컨텍스트를 하나의 마이크로서비스에 매핑할 수 있으면 더 좋다, 이는 컨텍스트가 실제로 경계되어 있음을
나타내는 것이다.

유비쿼터스 언어 : 마이크로서비스가 사용하는 언어가 유비쿼터스 언어임을 보장해야 하므로, 노출된 오퍼레이션과
인터페이스는 컨텍스트 도메인 언어로 표현된다.

컨텍스트 모델 : 비록 마이크로서비스가 제공하는 인터페이스에 노출되지 않는 엔티티라 하더라도, 마이크로서비스가
사용하는 모델은 경계된 컨텍스트 내에서 정의되야 하고, 유비쿼터스 언어를 사용해야 한다.
컨텍스트 매핑: 마지막으로 마이크로서비스의 의존성과 결합을 이해하기 위해 전체 시스템의 컨텍스트 매핑을 검토해야한다.

 * 마이크로서비스는 비즈니스 역량을 중심으로 모델링되며, 컨텍스트 매핑에서 보여주는 바와 같이 컨텍스트
도메인은 느슨하게 연결되며, 경계된 컨텍스트로서 단일 책임을 갖게 된다.
경계된 컨텍스트를 구현한 마이크로서비스는 구현을 쉽게 은닉할 수있으며, 자연히 격리되므로 독립적인 배포가 가능하다.


* 실행가능한 jar만들기

build/plugins 태그 아래에 POM을 수정


  true


spring application 설정에서 값 받아오기
@Value(value ="\${service.message.text}" //표현식 사용 "#{'\${service.message.text}' =='advance'}"
사용 $text

SERVICE.MESSAGE.TEXT="HELLO"


json 
직렬화 ‫SimpleObject("hi","kotlin")" 
복잡한 직렬화 ComplexObject(object1 = SimpleObject("more","complex"))
(data class ComplexObject(var object1 : SimpleObject? =null))

null 값 처리 어노테이션
@JsonInclude(Include.NON_NULL)
또는
spring.jackson.default-property-inclusion

'Spring' 카테고리의 다른 글

VS CODE (비쥬얼 스튜디오 코드에서) Spring boot 실행 (RUN)  (0) 2020.04.03
Spring 날짜 타입 변환  (0) 2019.06.24
Spring 동작원리  (0) 2019.02.27
HTTP Status 404 - /WEB-INF 에러  (0) 2019.02.25
Spring MVC 구성 요소  (0) 2019.02.23

+ Recent posts