Java 프로젝트에서 패키지 이름 지정에 어떤 전략을 사용하며 그 이유는 무엇입니까? [닫은]


88

나는 이것에 대해 얼마 전에 생각했고 최근에 내 가게가 첫 번째 실제 Java 웹 앱을 수행하면서 다시 나타났습니다.

소개로 두 가지 주요 패키지 명명 전략을 봅니다. (명확하게 말하면, 나는 이것의 전체 'domain.company.project'부분을 말하는 것이 아니라 그 아래의 패키지 규칙에 대해 이야기하고 있습니다.) 어쨌든, 내가 보는 패키지 명명 규칙은 다음과 같습니다.

  1. 기능적 : 비즈니스 도메인에 따른 ID가 아닌 구조적으로 기능에 따라 패키지 이름을 지정합니다. 이것에 대한 또 다른 용어는 '레이어'에 따른 이름 지정일 수 있습니다. 따라서 * .ui 패키지와 * .domain 패키지 및 * .orm 패키지가 있습니다. 패키지는 수직이 아닌 수평 슬라이스입니다.

    이것은 논리적 이름 지정보다 훨씬 일반적입니다. 사실 저는 이런 일을하는 프로젝트를 본 적이 없거나 들어 본 적이 없다고 생각합니다. 물론 이것은 내가 끔찍하게 똑똑하지 않고 모든 사람들이 자신이하는 방식으로 그렇게 할 큰 이유가 있다고 생각하기 때문에 (당신이 NP 문제에 대한 해결책을 생각해 냈다고 생각하는 것과 비슷하게) 저를 걱정스럽게 만듭니다. 반면에, 난 그냥 방에있는 코끼리 실종자에 반대 아니에요 그리고 나는 실제 인수 들어 본 적이 에 대한 이런 식의 이름을 지정할 패키지를하고. 사실상 표준 인 것 같습니다.

  2. 논리적 : 비즈니스 도메인 ID에 따라 패키지 이름을 지정 하고 해당 수직적 기능 조각과 관련된 모든 클래스를 해당 패키지에 넣습니다.

    나는 전에 언급했듯이 이것을 보거나 들어 본 적이 없지만 나에게는 의미가 있습니다.

    1. 저는 시스템에 수평이 아닌 수직으로 접근하는 경향이 있습니다. 데이터 액세스 계층이 아닌 주문 처리 시스템에 들어가서 개발하고 싶습니다. 당연히 그 시스템을 개발할 때 데이터 액세스 계층을 건드릴 가능성이 있지만 요점은 그렇게 생각하지 않는다는 것입니다. 물론 이것이 의미하는 바는 변경 명령을 받거나 새로운 기능을 구현하고 싶을 때 관련된 모든 클래스를 찾기 위해 여러 패키지에서 낚시를하지 않아도된다는 것입니다. 대신 X 패키지를 살펴 봅니다. 왜냐하면 내가하는 일은 X와 관련이 있기 때문입니다.

    2. 개발 관점에서 볼 때 패키지가 아키텍처가 아닌 비즈니스 도메인을 문서화하는 것이 큰 승리라고 생각합니다. 나는 도메인은 거의 항상 시스템의 아키텍처, 특히이 시점에서 구현에서 거의 평범 해지는 곳에서 찾기 어려운 시스템의 일부라고 느낍니다. 이런 유형의 명명 규칙을 사용하고 패키지 명명에서 즉시 시스템에 도달 할 수 있다는 사실은 주문, 고객, 기업, 제품 등을 처리한다는 것을 알기 때문에 매우 편리해 보입니다.

    3. 이렇게하면 Java의 액세스 수정자를 훨씬 더 잘 활용할 수있을 것 같습니다. 이를 통해 시스템의 계층이 아닌 하위 시스템에 인터페이스를 훨씬 더 명확하게 정의 할 수 있습니다. 따라서 투명하게 지속되기를 원하는 주문 하위 시스템이있는 경우 이론적으로는 dao 계층의 지속성 클래스에 대한 공용 인터페이스를 만들지 않고 대신 dao 클래스를 그것이 다루는 클래스들과 함께. 물론, 경우에 이 기능을 노출하고 싶어, 당신은 그것을위한 인터페이스를 제공하거나 공개 할 수 있습니다. 시스템 기능의 수직 조각을 여러 패키지로 분할하여 많은 것을 잃어버린 것처럼 보입니다.

    4. 내가 볼 수있는 한 가지 단점은 레이어를 찢어내는 것이 조금 더 어렵다는 것입니다. 패키지를 삭제하거나 이름을 변경 한 다음 대체 기술을 사용하여 새 패키지를 삭제하는 대신 모든 패키지의 모든 클래스를 변경해야합니다. 그러나 나는 이것이 큰 문제라고 생각하지 않습니다. 경험 부족 때문일 수도 있지만, 시스템 내에서 수직 기능 슬라이스를 편집하고 들어가는 횟수에 비해 기술을 교체하는 횟수가 적다는 것을 상상해야합니다.

그래서 질문이 당신에게 나올 것이라고 생각합니다. 당신은 패키지 이름을 어떻게 지정하고 왜 그럴까요? 내가 여기서 황금 거위 같은 것을 우연히 만났다고 생각하지는 않는다는 것을 이해하십시오. 나는 거의 학문적 경험으로이 모든 것에 대해 꽤 생소합니다. 그러나 나는 내 추론의 허점을 발견 할 수 없으므로 여러분 모두가 앞으로 나아갈 수 있기를 바랍니다.


내가 지금까지들은 것은 그것이 일종의 판단 호출임을 나타내는 것 같습니다. 그러나 대부분의 답변은 실질적인 고려 사항에 초점을 맞추지 않았습니다. 그게 제가 찾고있는 것입니다. 그래도 지금까지 도움을 주셔서 감사합니다!
Tim Visher

나는 그것이 판결 전화라고 생각하지 않습니다. 먼저 레이어로 나눈 다음 기능별로 나누는 것이 확실히 갈 길입니다. 내 대답을 업데이트하고 있습니다.
eljenso

@eljenso : Eclipse 녀석에게 알려주세요. :) Eclipse에서 첫 번째 부분은 배포 단위이자 기능인 "기능"입니다. "기능"내부에는 일반적으로 계층별로 구분되는 "플러그인"이 있지만 동일한 "기능"내의 플러그인은 항상 함께 배포해야합니다. 배포 단위가 하나 뿐인 경우 먼저 계층별로 나눈 다음 기능별로 만 나누는 것이 좋습니다. 배포 단위가 여러 개인 경우 프레젠테이션 계층 만 배포하는 것이 아니라 추가 기능을 원합니다.
Peter Štibraný

응용 프로그램의 비즈니스 계층과 관련된 특정 질문이 있습니다. 명명 규칙은 무엇입니까?
Bionix1441

답변:


32

패키지 디자인의 경우 먼저 레이어로 나눈 다음 다른 기능으로 나눕니다.

몇 가지 추가 규칙이 있습니다.

  1. 레이어는 가장 일반적인 (하단)에서 가장 구체적인 (상단)까지 쌓입니다.
  2. 각 레이어에는 공용 인터페이스 (추상화)가 있습니다.
  3. 레이어는 다른 레이어의 공용 인터페이스에만 의존 할 수 있습니다 (캡슐화).
  4. 레이어는보다 일반적인 레이어에만 의존 할 수 있습니다 (위에서 아래로의 종속성).
  5. 레이어는 바람직하게는 바로 아래에있는 레이어에 의존합니다.

예를 들어 웹 애플리케이션의 경우 애플리케이션 계층에 다음과 같은 계층이있을 수 있습니다 (위에서 아래로).

  • 프레젠테이션 레이어 : 클라이언트 계층에 표시 될 UI를 생성합니다.
  • 응용 프로그램 계층 : 응용 프로그램에 고유 한 논리 포함, 상태 저장
  • 서비스 계층 : 도메인별로 기능 그룹화, 상태 비 저장
  • 통합 계층 : 백엔드 계층 (db, jms, 이메일 등)에 대한 액세스를 제공합니다.

결과 패키지 레이아웃의 경우 다음과 같은 몇 가지 추가 규칙이 있습니다.

  • 모든 패키지 이름의 루트는 <prefix.company>.<appname>.<layer>
  • 레이어의 인터페이스는 기능에 따라 더 분할됩니다. <root>.<logic>
  • 레이어의 개인 구현은 private로 시작됩니다. <root>.private

다음은 레이아웃의 예입니다.

프레젠테이션 계층은보기 기술과 선택적으로 응용 프로그램 그룹으로 나뉩니다.

com.company.appname.presentation.internal
com.company.appname.presentation.springmvc.product
com.company.appname.presentation.servlet
...

애플리케이션 계층은 사용 사례로 나뉩니다.

com.company.appname.application.lookupproduct
com.company.appname.application.internal.lookupproduct
com.company.appname.application.editclient
com.company.appname.application.internal.editclient
...

서비스 계층은 백엔드 계층의 도메인 논리에 영향을받는 비즈니스 도메인으로 나뉩니다.

com.company.appname.service.clientservice
com.company.appname.service.internal.jmsclientservice
com.company.appname.service.internal.xmlclientservice
com.company.appname.service.productservice
...

통합 계층은 '기술'과 액세스 개체로 구분됩니다.

com.company.appname.integration.jmsgateway
com.company.appname.integration.internal.mqjmsgateway
com.company.appname.integration.productdao
com.company.appname.integration.internal.dbproductdao
com.company.appname.integration.internal.mockproductdao
...

이와 같은 패키지 분리의 장점은 복잡성을 관리하는 것이 더 쉽고 테스트 가능성과 재사용 가능성이 높아진다는 것입니다. 많은 오버 헤드처럼 보이지만 제 경험상 실제로는 매우 자연스럽고이 구조 (또는 이와 유사한)에 대해 작업하는 모든 사람이 며칠 만에이를 선택합니다.

수직적 접근이 그다지 좋지 않다고 생각하는 이유는 무엇입니까?

계층화 된 모델에서는 여러 다른 상위 수준 모듈이 동일한 하위 수준 모듈을 사용할 수 있습니다. 예를 들어, 동일한 애플리케이션에 대해 여러보기를 빌드 할 수 있고, 여러 애플리케이션이 동일한 서비스를 사용할 수 있으며, 여러 서비스가 동일한 게이트웨이를 사용할 수 있습니다. 여기서 트릭은 레이어를 이동할 때 기능 수준이 변경된다는 것입니다. 보다 구체적인 계층의 모듈은 표현하는 기능 수준이 1-1을 매핑하지 않기 때문에보다 일반적인 계층의 모듈에 1-1을 매핑하지 않습니다.

패키지 디자인에 수직적 접근 방식을 사용하는 경우, 즉 먼저 기능별로 구분 한 다음 서로 다른 수준 의 기능을 가진 모든 빌딩 블록을 동일한 '기능 재킷'에 넣습니다. 보다 구체적인 모듈을 위해 일반 모듈을 디자인 할 수 있습니다. 그러나 이것은 더 일반적인 레이어가 더 구체적인 레이어에 대해 알면 안된다는 중요한 원칙을 위반합니다. 예를 들어 서비스 계층은 애플리케이션 계층의 개념을 따라 모델링해서는 안됩니다.


"이러한 패키지 분리의 장점은 복잡성을 관리하는 것이 더 쉽고 테스트 가능성과 재사용 가능성이 높아진다는 것입니다." 당신은 정말로 이것이 왜 그런지에 대해 설명하지 않습니다.
mangoDrunk

1
그 이유를 이유로하지 않습니다 하지 않습니다 그래서. 그러나 어쨌든 ... 조직 규칙은 상당히 명확하고 간단하므로 복잡성이 줄어 듭니다. 조직 자체로 인해 더 테스트하고 재사용 할 수 있습니다. 누구나 시도해 볼 수 있으며 나중에 동의하거나 동의하지 않을 수 있습니다. 수평 적 접근이 더 쉽다고 생각하는 이유를 암시 적으로 설명하면서 수직적 접근 방식의 단점을 간략하게 설명합니다.
eljenso

8
이 기사에서는 package-by-layer 대신 package-by-feature 를 사용하는 것이 더 좋은 이유를 아주 잘 설명합니다 .
Tom

@eljenso "그렇지 않은 이유에 대해 설명하지 않습니다", 증명의 부담을 옮기려고? Tom이 게시 한 기사는 패키지 별 기능이 더 좋은 이유를 매우 잘 설명하고 "판단 호출이라고 생각하지 않습니다. 먼저 계층별로 나누고 다음으로 기능별로 나누는 것이 확실히 방법입니다. 갈 "을 진지하게.
pka 2013 년

18

저는 밥 삼촌의 패키지 디자인 원칙을 고수하고 있습니다. 요컨대, 함께 재사용되고 함께 변경 될 클래스 (예 : 종속성 변경 또는 프레임 워크 변경)는 동일한 패키지에 넣어야합니다. IMO, 기능적 분석은 대부분의 애플리케이션에서 수직적 / 비즈니스 별 분석보다 이러한 목표를 달성 할 가능성이 더 높습니다.

예를 들어, 도메인 객체의 수평 슬라이스는 여러 종류의 프런트 엔드 또는 애플리케이션에서 재사용 할 수 있으며 웹 프런트 엔드의 수평 슬라이스는 기본 웹 프레임 워크를 변경해야 할 때 함께 변경 될 수 있습니다. 반면에 다른 기능 영역의 클래스가 해당 패키지에 그룹화되어있는 경우 여러 패키지에서 이러한 변경 사항의 파급 효과를 상상하기 쉽습니다.

분명히 모든 종류의 소프트웨어가 동일하지는 않으며 특정 프로젝트에서 수직적 분류가 의미가있을 수 있습니다.


감사합니다, 이것은 매우 분명합니다. 제가 질문에서 말했듯이, 기술을 교체하는 횟수가 기능의 수직 조각을 중심으로 이동하는 것보다 훨씬 적다고 생각합니다. 이것은 당신의 경험이 아니 었습니까?
Tim Visher

기술에 관한 것만이 아닙니다. 원본 게시물의 1 번 요점은 수직 슬라이스가 일부 인터페이스 (SOA)를 통해 서로 통신하는 독립적 인 애플리케이션 / 서비스 인 경우에만 의미가 있습니다. 더 아래 ...
Buu Nguyen

이제 고유 한 GUI / 비즈니스 / 데이터가있는 세분화 된 각 앱 / 서비스의 세부 사항으로 이동하면 기술, 종속성, 규칙 / 워크 플로, 로깅에 대한 수직 조각의 변화를 상상할 수 없습니다. , 보안, UI 스타일은 다른 슬라이스와 완전히 분리 될 수 있습니다.
Buu Nguyen

나는 당신의 의견에 관심이있을 것입니다 내 대답
i3ensays

@BuuNguyen 패키지 디자인 원칙에 대한 링크가 깨졌습니다.
johnnieb

5

일반적으로 두 수준의 분할이 있습니다. 맨 위에서 배치 단위가 있습니다. 이것들은 '논리적으로'라고 명명됩니다 (당신의 용어로 Eclipse 기능을 생각하십시오). 배포 단위 내부에는 패키지의 기능적 분할이 있습니다 (Eclipse 플러그인을 생각해보십시오).

예를 들어 기능은 com.feature이고 com.feature.client, com.feature.corecom.feature.ui플러그인으로 구성됩니다 . 플러그인 내부에는 다른 패키지와 거의 구분이 없지만 그다지 드문 일은 아닙니다.

업데이트 : Btw, InfoQ : http://www.infoq.com/presentations/code-organization-large-projects 에서 코드 구성에 대한 Juergen Hoeller의 멋진 이야기가 있습니다. Juergen은 Spring의 건축가 중 한 명이며, 이것에 대해 많은 것을 알고 있습니다.


나는 잘 따르지 않는다. 일반적으로 com.apache.wicket.x를 볼 수 있으며 여기서 x는 기능적이거나 논리적입니다. 나는 보통 com.x를 보지 못한다. com.company.project.feature.layer 구조로 갈 것이라고 말하는 것 같습니까? 이유가 있습니까?
Tim Visher

이유는 "com.company.project.feature"가 배포 단위이기 때문입니다. 이 수준에서 일부 기능은 선택 사항이며 건너 뛸 수 있습니다 (예 : 배포되지 않음). 그러나 내부 기능은 선택 사항이 아니며 일반적으로 모든 것을 원합니다. 여기서 레이어별로 나누는 것이 더 합리적입니다.
Peter Štibraný

4

내가 작업 한 대부분의 자바 프로젝트는 먼저 자바 패키지를 기능적으로 슬라이스 한 다음 논리적으로 슬라이스합니다.

일반적으로 부품은 별도의 빌드 아티팩트로 분할 될만큼 충분히 크며, 여기서 핵심 기능을 하나의 항아리에, API를 다른 항아리에, 웹 프런트 엔드 항목을 warfile에 넣을 수 있습니다.


어떤 모습일까요? domain.company.project.function.logicalSlice?
Tim Visher

꽤 많이! egdcpweb.profiles, dcpweb.registration, dcpapis, dcppersistence 등은 일반적으로 꽤 잘 작동하며 마일리지는 다를 수 있습니다. 도메인 모델링을 사용하는지 여부도 다릅니다. 여러 도메인이있는 경우 먼저 도메인별로 분할 할 수 있습니다.
Ben Hardy

나는 개인적으로 반대의 논리적이고 기능적인 것을 선호합니다. apples.rpc, apples.model 및 banana.model, banana.store
mP.

모든 웹 자료를 함께 그룹화하는 것보다 모든 사과 자료를 함께 그룹화 할 수있는 것이 더 많은 가치가 있습니다.
mP.

3

패키지는 하나의 단위로 컴파일되고 배포됩니다. 패키지에 속한 클래스를 고려할 때 주요 기준 중 하나는 종속성입니다. 이 클래스가 의존하는 다른 패키지 (타사 라이브러리 포함) 잘 구성된 시스템은 패키지에서 유사한 종속성을 가진 클래스를 클러스터합니다. 이렇게하면 잘 정의 된 몇 개의 패키지 만 종속되기 때문에 하나의 라이브러리에서 변경으로 인한 영향을 제한합니다.

논리적이고 수직적 인 시스템이 대부분의 패키지에서 종속성을 "번짐"하는 경향이있는 것처럼 들립니다. 즉, 모든 기능이 수직 슬라이스로 패키징 된 경우 모든 패키지는 사용하는 모든 타사 라이브러리에 종속됩니다. 라이브러리에 대한 모든 변경 사항은 전체 시스템에 영향을 미칠 수 있습니다.


아. 따라서 수평 슬라이스를 수행하는 한 가지 작업은 사용중인 라이브러리의 실제 업그레이드로부터 사용자를 보호하는 것입니다. 수직 슬라이스가 시스템이 모든 패키지에 대해 갖는 모든 종속성을 더럽히는 것이 옳다고 생각합니다. 이것이 왜 그렇게 큰 일입니까?
Tim Visher

"기능"의 경우 그렇게 큰 문제는 아닙니다. 그들은 더 변동적이고 어쨌든 더 많은 종속성을 갖는 경향이 있습니다. 반면에이 "클라이언트"코드는 재사용 가능성이 낮은 경향이 있습니다. 재사용 가능한 라이브러리가 되려는 경우, 작은 변화마다 클라이언트를 격리하는 것은 큰 투자입니다.
erickson

3

나는 개인적으로 각 기능적 참여에 대한 하위 패키지를 포함하는 클래스를 논리적으로 그룹화하는 것을 선호합니다.

포장의 목표

패키지는 결국 사물을 그룹화하는 것입니다. 관련 클래스라는 아이디어는 서로 가깝게 살고 있습니다. 동일한 패키지에 거주하는 경우 비공개 패키지를 활용하여 가시성을 제한 할 수 있습니다. 문제는 모든 관점과 인내를 하나의 패키지로 묶으면 많은 클래스가 단일 패키지로 뒤섞 일 수 있다는 것입니다. 다음으로 할 수있는 일은 뷰, 지속성, util 하위 패키지를 만들고 그에 따라 클래스를 리팩터링하는 것입니다. 불행히도 보호되고 패키지 개인 범위 지정은 이러한 가시성 규칙을 시행하는 데 도움이되는 현재 패키지 및 하위 패키지의 개념을 지원하지 않습니다.

이제 모든 뷰 관련 항목을 그룹화하기 위해 어떤 값이 있는지 기능을 통해 분리 된 값을 볼 수 있습니다. 이 이름 지정 전략의 항목은 뷰의 일부 클래스와 연결이 끊어지고 다른 클래스는 지속성에 있습니다.

내 논리적 패키징 구조의 예

설명을 위해 두 모듈의 이름을 지정합니다. 패키지 트리의 특정 분기 아래에 클래스를 그룹화하는 개념으로 모듈 이름을 사용합니다.

apple.model apple.store banana.model banana.store

장점

Banana.store.BananaStore를 사용하는 클라이언트는 우리가 제공하고자하는 기능에만 노출됩니다. 최대 절전 버전은 인식 할 필요가없고 스토리지 작업에 혼란을 추가 할 때 이러한 클래스를 볼 필요가없는 구현 세부 사항입니다.

기타 논리적 v 기능적 이점

루트로 갈수록 범위가 더 넓어지고 하나의 패키지에 속한 것이 모듈에 속한 것들에 점점 더 많은 종속성을 나타 내기 시작합니다. 예를 들어 "banana"모듈을 조사한다면 대부분의 종속성은 해당 모듈 내로 제한됩니다. 실제로 "banana"아래의 대부분의 도우미는이 패키지 범위 밖에서 전혀 참조되지 않습니다.

왜 기능성?

기능을 기반으로 한 항목을 묶음으로써 어떤 가치를 얻을 수 있습니까? 이러한 경우 대부분의 클래스는 서로 독립적이며 패키지 전용 메서드 또는 클래스를 사용할 필요가 거의 없습니다. 그것들을 자체 서브 패키지로 리팩토링하는 것은 거의 이득이 없지만 혼란을 줄이는 데 도움이됩니다.

시스템에 대한 개발자 변경

개발자가 사소한 것 이상의 변경 작업을 수행 할 때 잠재적으로 패키지 트리의 모든 영역에서 파일을 포함하는 변경 사항이 있다는 것은 어리석은 것처럼 보입니다. 논리적 구조적 접근 방식을 사용하면 변경 사항이 패키지 트리의 동일한 부분 내에서 더 국지적으로 나타납니다.


"개발자가 패키지 트리의 모든 영역에서 파일을 [...] 할 때." 이것이 어리석은 것 같다고 말하는 것이 맞습니다. 이것이 바로 적절한 계층화의 요점이기 때문입니다. 변경 사항 애플리케이션의 전체 구조에 파급 되지 않습니다 .
eljenso

조언 해주셔서 감사합니다. 당신을 명확하게 이해하고 있는지 잘 모르겠습니다. 나는 당신이 논리 패키지에 대해 논쟁을 시도하고 있다고 믿습니다. 나는 그 이유를 정확히 알지 못합니다. 답변을 좀 더 명확하게 해주실 수 있나요? 감사!
Tim Visher

3

기능 (건축)과 논리 (기능) 포장 장소가 접근한다. 많은 예제 응용 프로그램 (교과서 등에서 볼 수 있음)은 프레젠테이션, 비즈니스 서비스, 데이터 매핑 및 기타 아키텍처 계층을 별도의 패키지에 배치하는 기능적 접근 방식을 따릅니다. 예제 응용 프로그램에서 각 패키지에는 종종 클래스가 몇 개 또는 하나만 있습니다.

이 초기 접근법은 인위적인 예제가 종종 다음과 같은 역할을하기 때문에 괜찮습니다. 1) 제시되는 프레임 워크의 아키텍처를 개념적으로 매핑하고, 2) 단일 논리적 목적으로 수행됩니다 (예 : 클리닉에서 애완 동물 추가 / 제거 / 업데이트 / 삭제). . 문제는 많은 독자들이 이것을 한계가없는 표준으로 받아들이는 것입니다.

"비즈니스"응용 프로그램이 점점 더 많은 기능을 포함하도록 확장됨에 따라 기능적 접근 방식을 따르는 것은 부담이됩니다. 아키텍처 계층 (예 : "web"또는 "ui"패키지 아래의 웹 컨트롤러 등)을 기반으로 유형을 찾을 위치를 알고 있지만 단일 논리 기능을 개발 하려면 여러 패키지 사이를 앞뒤로 건너 뛰어야합니다. 이것은 최소한 성가신 일이지만 그보다 더 나쁩니다.

논리적으로 관련된 유형은 함께 패키징되지 않기 때문에 API가 지나치게 공개됩니다. 논리적으로 관련된 유형 간의 상호 작용은 유형이 서로 가져오고 상호 작용할 수 있도록 '공개'로 강제됩니다 (기본 / 패키지 가시성을 최소화하는 기능이 손실 됨).

프레임 워크 라이브러리를 구축하고 있다면 반드시 내 패키지가 기능 / 아키텍처 패키징 접근 방식을 따를 것입니다. 내 API 소비자는 import 문에 아키텍처 이름을 따서 명명 된 직관적 인 패키지가 포함되어 있다는 사실을 인식 할 수도 있습니다.

반대로 비즈니스 애플리케이션을 빌드 할 때는 기능별로 패키징합니다. Widget, WidgetService 및 WidgetController를 모두 동일한 " com.myorg.widget. "패키지에 배치 한 다음 기본 가시성을 활용하는 데 문제가 없습니다 (패키지 간 종속성뿐 아니라 import 문이 더 적음).

그러나 교차 사례가 있습니다. 내 WidgetService가 여러 논리 도메인 (기능)에서 사용되는 경우 " com.myorg.common.service. "패키지를 만들 수 있습니다 . 또한 여러 기능에서 재사용 할 수 있도록 클래스를 만들고 " com.myorg.common.ui.helpers. "및 " com.myorg.common.util. " 과 같은 패키지로 끝날 수도 있습니다 . 나중에 이러한 모든 "공통"클래스를 별도의 프로젝트로 이동하여 비즈니스 응용 프로그램에 myorg-commons.jar 종속성으로 포함시킬 수도 있습니다.


2

논리적 프로세스의 세분화에 달려 있습니까?

독립 실행 형인 경우 새 패키지가 아닌 소스 제어에 새 프로젝트가있는 경우가 많습니다.

내가 현재 진행중인 프로젝트는 논리적 분할에 대한 오류입니다. 자이 썬 측면을위한 패키지, 규칙 엔진을위한 패키지, foo, bar, binglewozzle 등을위한 패키지가 있습니다. / writers는 XML 패키지 (이전에 수행 한 작업)를 갖지 않고 해당 패키지 내의 각 모듈에 대해 작성하지만 공유 논리가가는 핵심 XML 패키지는 여전히 존재합니다. 그러나 이에 대한 한 가지 이유는 확장 가능 (플러그인) 할 수 있으므로 각 플러그인은 XML (또는 데이터베이스 등) 코드도 정의해야하므로이를 중앙 집중화하면 나중에 문제가 발생할 수 있습니다.

결국 그것은 특정 프로젝트에 가장 합리적으로 보이는 것 같습니다. 그러나 일반적인 프로젝트 계층 다이어그램의 라인을 따라 패키징하는 것은 쉽다고 생각합니다. 논리적이고 기능적인 패키징의 혼합으로 끝날 것입니다.

필요한 것은 태그가 지정된 네임 스페이스입니다. 일부 Jython 기능에 대한 XML 구문 분석기는 둘 중 하나를 선택하지 않고 Jython과 XML 모두에 태그를 지정할 수 있습니다.

아니면 내가 흔들고있을 수도 있습니다.


나는 당신의 요점을 완전히 이해하지 못합니다. 당신이 말하는 것은 당신의 프로젝트에 가장 합당한 일을하고 당신을 위해 논리적 인 일을해야한다는 것입니다. 그것은 약간의 기능을 내포하고 있습니다. 이것에 대한 구체적인 실제적인 이유가 있습니까?
Tim Visher

내가 말했듯이 내장 기능을 강화하는 플러그인을 갖게 될 것입니다. 플러그인은 기능을 제공 할뿐만 아니라 XML (그리고 결국에는 DB에)을 구문 분석하고 쓸 수 있어야합니다. 따라서 com.xx.feature.xml 또는 com.xx.xml.feature가 있습니까? 전자는 깔끔해 보인다.
JeeBee

2

나는 종속성 그래프를 그리면 가능한 한 적은 순환 참조로 일관된 패턴을 따르고 사용하기 쉬운 방식으로 패키지 구조를 설계하려고합니다.

나에게는 수평이 아닌 수직 명명 시스템에서 유지 관리하고 시각화하는 것이 훨씬 쉽습니다. component1.display에 component2.dataaccess에 대한 참조가 있으면 display.component1에 dataaccess에 대한 참조가있을 때보 다 더 많은 경고 벨이 울립니다. component2.

물론 두 사람이 공유하는 구성 요소는 자체 패키지로 이동합니다.


그때 내가 이해했듯이 수직 명명 규칙을 옹호 할 것입니다. 여러 슬라이스에 걸쳐 클래스가 필요할 때 * .utils 패키지의 용도라고 생각합니다.
Tim Visher

2

나는 논리적 ( "기능별") 조직을 전적으로 따르고 제안합니다! 패키지는 가능한 한 "모듈"의 개념을 따라야합니다. 기능적 조직은 프로젝트 전체에 모듈을 분산하여 캡슐화를 줄이고 구현 세부 사항을 변경하는 경향이 있습니다.

예를 들어 Eclipse 플러그인을 살펴 보겠습니다. 모든보기 또는 작업을 하나의 패키지에 넣는 것은 엉망입니다. 대신 기능의 각 구성 요소는 기능의 패키지로 이동해야하며, 많은 경우 하위 패키지 (featureA.handlers, featureA.preferences 등)로 이동해야합니다.

물론, 문제는 계층 적 패키지 시스템 (다른 것들 중에서 Java가 가지고 있음)에 있습니다.이 시스템은 직교 문제를 처리하는 것을 불가능하거나 적어도 매우 어렵게 만듭니다.


1

나는 개인적으로 기능적 명명을 할 것입니다. 짧은 이유는 코드 중복이나 의존성 악몽을 피할 수 있다는 것입니다.

좀 더 자세히 설명하겠습니다. 자체 패키지 트리가있는 외부 jar 파일을 사용하면 어떻게됩니까? (컴파일 된) 코드를 프로젝트로 효율적으로 가져오고 있으며 (기능적으로 분리 된) 패키지 트리를 사용합니다. 두 가지 명명 규칙을 동시에 사용하는 것이 합리적입니까? 아니, 그것이 당신에게 숨겨지지 않았다면. 프로젝트가 충분히 작고 단일 구성 요소가있는 경우입니다. 그러나 논리 단위가 여러 개인 경우 데이터 파일로드 모듈을 다시 구현하고 싶지 않을 것입니다. 논리적 단위간에 공유하고 논리적으로 관련되지 않은 단위간에 인위적인 종속성이 없으며 특정 공유 도구를 배치 할 단위를 선택할 필요가 없습니다.

이것이 기능적 이름 지정이 특정 크기에 도달하거나 도달 할 예정인 프로젝트에서 가장 많이 사용되는 이유이며, 특정 역할을 추적하기 위해 클래스 이름 지정 규칙에서 논리적 이름 지정이 사용됩니다. 꾸러미.

논리적 명명에 대한 귀하의 각 요점에 더 정확하게 응답하려고 노력할 것입니다.

  1. 계획을 변경할 때 기능을 수정하기 위해 이전 클래스에서 낚시를해야한다면 이는 잘못된 추상화의 신호입니다. 잘 정의 된 기능을 제공하는 클래스를 짧은 문장으로 정의해야합니다. 소수의 최상위 클래스 만이 비즈니스 인텔리전스를 반영하기 위해 이러한 모든 것을 조합해야합니다. 이렇게하면 더 많은 코드를 재사용하고 유지 관리가 더 쉬우 며 문서가 명확 해지고 종속성 문제가 줄어 듭니다.

  2. 그것은 주로 프로젝트를 진행하는 방식에 달려 있습니다. 확실히 논리적이고 기능적인 관점은 직교합니다. 따라서 하나의 명명 규칙을 사용하는 경우 순서를 유지하기 위해 다른 하나를 클래스 이름에 적용하거나 한 명명 규칙에서 다른 명명 규칙으로 어느 정도 깊이 포크해야합니다.

  3. 액세스 한정자는 처리 를 이해하는 다른 클래스가 클래스 내부에 액세스 할 수 있도록 허용하는 좋은 방법 입니다. 논리적 관계는 알고리즘 또는 동시성 제약에 대한 이해를 의미하지 않습니다. 기능적 일 수 있지만 그렇지 않습니다. 퍼블릭 및 프라이빗 이외의 액세스 수정자는 종종 적절한 아키텍처 및 클래스 추상화의 부족을 숨기기 때문에 매우 지쳤습니다.

  4. 크고 상업적인 프로젝트에서 기술 변화는 당신이 생각하는 것보다 더 자주 발생합니다. 예를 들어, 저는 이미 XML 파서의 3 배, 캐싱 기술의 2 배, 지리적 위치 화 소프트웨어의 2 배를 변경해야했습니다. 전용 패키지에 모든 세부 사항을 숨겼습니다.


1
내가 틀렸다면 용서해주세요.하지만 많은 사람들이 사용하도록 고안된 프레임 워크를 개발하는 것에 대해 더 많이 이야기하는 것 같습니다. 이러한 유형의 개발과 최종 사용자 시스템 개발간에 규칙이 바뀐다 고 생각합니다. 내가 잘못?
Tim Visher

많은 수직 슬라이스에서 사용되는 공통 클래스의 경우 utils패키지 와 같은 것을 갖는 것이 합리적이라고 생각 합니다. 그런 다음이를 필요로하는 모든 클래스는 해당 패키지에 의존 할 수 있습니다.
Tim Visher

다시 한 번, 크기가 중요합니다. 프로젝트가 충분히 커지면 여러 사람이 지원해야하며 어떤 종류의 전문화가 발생합니다. 상호 작용을 용이하게하고 실수를 방지하기 위해 프로젝트를 부분적으로 분할하는 것이 빠르게 필요합니다. 그리고 utils 패키지는 곧 거대해질 것입니다!
Varkhan

1

패키지를 전혀 사용하지 않는 것은 흥미로운 실험입니다 (루트 패키지 제외).

그때 발생하는 질문은 패키지를 도입하는 것이 언제, 왜 타당하다는 것입니다. 아마도 그 대답은 프로젝트를 시작할 때 대답했던 것과 다를 것입니다.

패키지는 카테고리와 같고 때로는 둘 중 하나를 결정하기가 어렵 기 때문에 귀하의 질문이 전혀 발생한다고 생각합니다. 때때로 태그는 클래스가 많은 상황에서 사용 가능하다는 것을 전달하는 데 더 감사 할 것입니다.


0

순전히 실용적인 관점에서, 자바의 가시성 구조는 접근 방법과 가진 속성에 동일한 패키지의 클래스 수 protecteddefault가시성뿐만 아니라 public사람을. 완전히 다른 코드 레이어에서 비공개 메서드를 사용하는 것은 확실히 큰 코드 냄새가 될 것입니다. 그래서 같은 레이어의 클래스를 같은 패키지에 넣는 경향이 있습니다.

나는 클래스에 대한 단위 테스트를 제외하고는 이러한 보호 또는 기본 메서드를 다른 곳에서 자주 사용하지 않지만, 그렇게 할 때 항상 동일한 레이어의 클래스에서 가져온 것입니다.


항상 다음 계층에 의존하는 것이 다 계층 시스템의 특성이 아닌가? 예를 들어 UI는 도메인 레이어 등에 의존하는 서비스 레이어에 의존합니다. 수직 슬라이스를 함께 패키징하면 과도한 패키지 간 종속성으로부터 보호되는 것처럼 보입니다.
Tim Visher

거의 보호 및 기본 방법을 사용하지 않습니다. 99 %는 공개 또는 비공개입니다. 일부 예외 : (1) 단위 테스트에서만 사용되는 메서드에 대한 기본 가시성, (2) 추상 기본 클래스에서만 사용되는 보호 된 추상 메서드.
Esko Luontola

1
Tim Visher, 종속성이 항상 같은 방향을 가리키고 종속성 그래프에주기가없는 한 패키지 간의 종속성은 문제가되지 않습니다.
Esko Luontola

0

때에 따라 다르지. 제 업무에서는 기능 (데이터 액세스, 분석) 또는 자산 클래스 (신용, 주식, 이자율)별로 패키지를 분할하는 경우가 있습니다. 팀에 가장 편리한 구조를 선택하기 만하면됩니다.


어느 쪽이든 갈 이유가 있습니까?
Tim Visher

자산 클래스별로 (보다 일반적으로 : 비즈니스 도메인별로) 분할하면 새로운 사용자가 코드를 통해 길을 쉽게 찾을 수 있습니다. 기능별 분할은 캡슐화에 좋습니다. 저에게 Java의 "패키지"액세스는 C ++의 "친구"와 비슷합니다.
quant_dev

@quant_dev 나는 "..by function is good for encapsulation"에 동의하지 않습니다. 완전히 반대가 사실이라고 생각합니다. 또한 "편리함"만 선택하지 마십시오. 각각에 대한 사례가 있습니다 (내 답변 참조).
i3ensays

-3

제 경험상, 재사용 성은 해결하는 것보다 더 많은 문제를 만듭니다. 최신의 저렴한 프로세서와 메모리를 사용하면 재사용을 위해 긴밀하게 통합하는 것보다 코드 복제를 선호합니다.


5
코드 재사용은 하드웨어 가격이 아니라 코드 유지 관리 비용에 관한 것입니다.
user2793390

1
동의하지만 간단한 모듈에서 수정하는 것이 전체 코드에 영향을주지는 않습니다. 어떤 유지 비용에 대해 이야기하고 있습니까?
Raghu Kasturi 2014

1
모듈의 버그 수정은 전체 애플리케이션에 영향을 미칩니다. 동일한 버그를 여러 번 수정하려는 이유는 무엇입니까?
user2793390
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.