리팩토링 후 팀에서 빈번한 오류를 피하려면 어떻게해야합니까?


20

약간의 배경 지식을 제공하기 위해 : 대략 12 명의 Ruby on Rails 개발자 (+/- 인턴)를 가진 회사에서 일합니다. 원격 작업이 일반적입니다. 우리의 제품은 두 가지 부분으로 구성되어 있습니다 : 오히려 뚱뚱한 핵심과 그 위에 세워진 큰 고객 프로젝트까지 얇습니다. 고객 프로젝트는 일반적으로 핵심을 확장합니다. 주요 기능을 덮어 쓰지 않습니다. 코어에는 리팩토링이 절실히 필요한 일부 나쁜 부분이 있다고 덧붙였습니다. 사양은 있지만 대부분 고객 프로젝트에 적용됩니다. 코어의 최악의 부분은 테스트되지 않은 것입니다 (그렇지 않아야합니다 ...).

개발자는 두 개의 팀으로 나뉘며 각 스프린트마다 하나 또는 두 개의 PO로 작업합니다. 일반적으로 하나의 고객 프로젝트는 팀 및 PO 중 하나와 엄격하게 연관됩니다.

이제 우리의 문제 : 오히려 자주 서로의 문제를 해결합니다. 팀 A의 누군가가 핵심 기능 Y를 확장하거나 리팩터링하여 팀 B의 고객 프로젝트 중 하나에 예기치 않은 오류가 발생합니다. 대부분 변경 사항이 팀 전체에 발표되지 않으므로 버그는 거의 항상 예상치 못한 것입니다. PO를 포함한 팀 B는 기능 Y가 안정적이라고 생각하고 변경 사항을 알지 못하고 릴리스하기 전에 테스트하지 않았습니다.

이러한 문제를 해결하는 방법은 무엇입니까? 어떤 종류의 '발표 기술'을 추천 해 주시겠습니까?


34
확실한 대답은 TDD 입니다.
mouviciel

1
어떻게 그 "키 기능을 덮어 쓰기하는 것은 발생하지 않습니다"상태 제공, 다음 문제는 점이다 않는 일이? 팀에서 "핵심"기능과 "핵심 기능"을 구분하고 있으며 어떻게 수행합니까? 상황을 이해하려고 노력하는 중 ...
logc

4
@mouvciel 그것은 동적 타이핑을 사용하지 않지만 ,이 경우에는 약간의 조언이 너무 늦습니다.
Doval

3
OCaml과 같은 강력한 형식의 언어를 사용하십시오.
Gaius

@ logc 명확하지 않을 수 있습니다. 죄송합니다. 필터 라이브러리 자체와 같은 핵심 기능을 덮어 쓰지 않지만 고객 프로젝트에서 사용하는 클래스에 새 필터를 추가합니다. 하나의 일반적인 시나리오는 필터 라이브러리의 변경으로 인해 고객 프로젝트에서 추가 된 필터가 손상 될 수 있습니다.
SDD64

답변:


24

Michael C. Feathers의 레거시 코드로 효과적으로 작업하기를 읽는 것이 좋습니다 . 자동화 된 테스트가 필요하고 쉽게 추가 할 수있는 방법, 아직없는 경우 리 코드하기 위해 어떤 "코드 냄새"가 필요한지 설명합니다.

게다가, 당신의 상황에서 또 다른 핵심 문제는 두 팀 간의 의사 소통이 부족한 것 같습니다. 이 팀은 얼마나 큽니까? 그들은 서로 다른 백 로그에서 작업하고 있습니까?

아키텍처에 따라 팀을 분할하는 것은 거의 항상 나쁜 습관입니다. 핵심 팀과 비 핵심 팀. 대신 기능 영역에서 팀을 만들고 구성 요소 간을 만들었습니다.


나는 "신화적인 인간-월"에서 코드 구조가 일반적으로 팀 / 조직 구조를 따른다는 것을 읽었습니다. 따라서 이것은 실제로 "나쁜 습관"이 아니라 일반적으로 진행되는 방식입니다.
Marcel

" 소프트웨어 개발의 역학 "에서 Visual C ++의 관리자는 기능 팀을 생생하게 추천합니다. 나는 "신화적인 남자-월", @Marcel을 읽지 못했지만 AFAIK는 업계에서 나쁜 관행을 나열합니다 ...
logc

Marcel, 이것이 일반적으로 진행되는 방식이지만 사실 더 많은 팀 (예 : 기능 팀)이 다르게하고 있습니다. 구성 요소 기반 팀이 있으면 교차 구성 요소 기능에 대해 작업 할 때 통신이 부족합니다. 그 뒤에는 거의 항상 좋은 아키텍처의 목적에 기반한 것이 아니라 다른 팀 / 구성 요소에 책임을 부여하려는 사람들이 아키텍처 토론을하게됩니다. 따라서이 질문의 저자가 묘사 한 상황을 얻을 수 있습니다. mountaingoatsoftware.com/blog/the-benefits-of-feature-teams 도 참조하십시오 .
Tohnmeister 2012 년

글쎄, 내가 OP를 이해하는 한, 팀은 핵심 팀과 비 핵심 팀으로 나뉘 지 않았다고 말했다 . 팀은 "고객 별"로 나뉘며 본질적으로 "기능별"입니다. 그리고 그것은 문제의 일부입니다. 모든 팀이 공통 핵심을 변경할 수 있기 때문에 한 팀의 변경 사항이 다른 팀에 영향을 미칩니다.
Doc Brown

@DocBrown 당신이 맞아요. 각 팀은 핵심을 변경할 수 있습니다. 물론 이러한 변화는 각 프로젝트에 도움이 될 것입니다. 그러나 서로 다른 백 로그에서 작동합니다. 각 고객 당 하나, 핵심 고객 당 하나가 있습니다.
SDD64

41

우리는 코어의 최악의 부분이 테스트되지 않았습니다.

이게 문제 야. 효율적인 리팩토링은 일련의 자동화 된 테스트에 크게 좌우됩니다. 그것들이 없으면 설명하는 문제가 나타나기 시작합니다. 이는 메소드를 매개 변수를 전달하는 것과 관련된 기본 오류를 포착 할 컴파일러가없는 Ruby와 같은 동적 언어를 사용하는 경우 특히 중요합니다.


10
베이비 단계에서 리팩토링하고 매우 자주 커밋합니다.
Stefan Billiet

1
여기에 조언을 추가 할 수있는 조언이 많이 있지만,이 시점까지 모두 다룰 것입니다. OP가 "그 자체로"농담 자체가 문제라는 것을 보여주는 농담에 대해서는 스크립팅 된 테스트가 리팩토링에 미치는 영향은 엄청납니다. 패스가 실패하면 리팩토링이 작동하지 않았습니다. 모든 패스가 패스로 남아 있으면 리팩토링 이 작동 했을 수 있습니다 (이동 실패는 분명히 플러스이지만 모든 패스를 패스로 유지하는 것이 nett 이득보다 중요합니다. 하나의 테스트를 중단하고 5를 수정하는 변경은 개선, 그러나 리팩토링은 아님)
Jon Hanna

나는 당신에게 "+1"을 주었지만 "자동화 된 테스트"만이 이것을 해결하는 유일한 방법은 아니라고 생각합니다. 더 나은 수동이지만 체계적인 QA는 별도의 QA 팀이 품질 문제를 해결할 수도 있습니다 (자동 테스트 수동 테스트 모두 가능 ).
Doc Brown

좋은 점이지만 핵심 프로젝트와 고객 프로젝트가 별도의 모듈 (그리고 Ruby와 같은 동적 언어) 인 경우 핵심은 테스트와 관련 구현을 모두 변경 하고 자체 테스트에 실패하지 않고 종속 모듈을 중단 할 수 있습니다 .
logc

다른 사람들이 언급했듯이. TDD. 아마도 가능한 많은 코드에 대한 단위 테스트가 있어야한다는 것을 이미 알고있을 것입니다 . 단위 테스트를 작성하는 것은 리소스 낭비이므로 구성 요소 리팩토링을 시작할 때 핵심 코드를 만지기 전에 광범위한 테스트 작성으로 시작해야합니다.
jb510

5

더 나은 단위 테스트를 지시하는 이전 답변은 좋지만 더 근본적인 문제가 있다고 생각합니다. 고객 프로젝트 코드에서 핵심 코드에 액세스하려면 명확한 인터페이스가 필요합니다. 이런 식으로 인터페이스를 통해 관찰 된 동작을 변경하지 않고 핵심 코드를 리팩터링 하면 다른 팀의 코드가 중단되지 않습니다. 이를 통해 "안전하게"리팩토링 할 수있는 것과 인터페이스를 깨뜨릴 수있는 디자인이 필요한 것이 무엇인지 쉽게 알 수 있습니다.


에 딱 맞다. 보다 자동화 된 테스트는 이점 만 가져다 줄뿐 아니라 그만한 가치가 있지만 핵심 변경 사항을 전달하지 못하는 핵심 문제는 해결하지 못합니다. 중요한 기능에 인터페이스를 래핑하여 분리하면 크게 개선됩니다.
Bob Tway

5

다른 답변은 중요한 포인트 (더 많은 단위 테스트, 기능 팀, 핵심 구성 요소에 대한 깨끗한 인터페이스)를 강조했지만 버전이 누락 된 것으로 나타났습니다.

릴리스 1 을 수행하여 코어의 동작을 정지시키고 해당 릴리스를 개인 아티팩트 관리 시스템 2에 넣으면 모든 고객 프로젝트가 코어 버전 X 에 대한 종속성을 선언 할 수 있으며 다음 릴리스 X에 의해 중단되지 않습니다. + 1 .

"발표 정책"은 각 릴리스와 함께 CHANGES 파일을 갖거나 팀 회의를 통해 새로운 각 코어 릴리스의 모든 기능을 발표하는 것으로 줄어 듭니다.

또한 "핵심"을 정의하고 그 핵심 부분을 "핵심"으로 더 잘 정의해야한다고 생각합니다. "핵심 구성 요소"를 많이 변경하지 않는 것처럼 보이지만 "핵심"을 자주 변경할 수 있습니다. 무언가에 의존하기 위해서는 안정된 상태를 유지해야합니다. 무언가가 안정되지 않으면 그것을 핵심이라고 부르지 마십시오. 어쩌면 "도움말"구성 요소라고 할 수 있습니까?

편집 : 시맨틱 버전 관리 시스템 의 규칙을 따르는 경우 코어 API의 호환되지 않는 변경 사항은 주요 버전 변경 사항 으로 표시되어야합니다 . 즉, 기존 코어의 동작을 변경하거나 무언가를 제거 할 때 단순히 새로운 것을 추가하는 것이 아닙니다. 이러한 규칙을 통해 개발자는 '1.1'에서 '1.2'로 업데이트하는 것이 안전하지만 '1.X'에서 '2.0'으로 변경하는 것은 위험하므로 신중하게 검토해야합니다.

1 : 나는 이것이 Ruby의 세계에서 보석이라고 생각합니다
.Java의 Nexus 또는 Python의 PyPI와 같습니다.


"버전 관리"는 실제로 중요하지만 릴리스 전에 코어를 고정하여 설명 된 문제를 해결하려고하면 정교한 분기 및 병합이 필요합니다. 그 이유는 팀 A의 "릴리스 빌드"단계에서 A가 코어를 변경해야 할 수도 있지만 (적어도 버그 수정을 위해) 다른 팀의 코어에 대한 변경을 허용하지 않기 때문입니다. 기술 부채의 한 형태 인 "나중에"합병 될 팀당 핵심. 때로는 괜찮지 만 나중에 설명 된 문제를 연기합니다.
Doc Brown

@DocBrown : 나는 당신에 동의하지만, 모든 개발자들이 협력하고 성장한다는 가정하에 썼습니다. 이것은 내가 당신이 묘사 한 것을 보지 못했다고 말하는 것이 아닙니다 . 그러나 시스템을 신뢰할 수있게 만드는 핵심 요소는 안정성을 위해 노력하는 것입니다. 또한 팀 A가 코어에서 X를 변경해야하고 팀 B가 코어에서 X를 변경해야하는 경우 X가 코어에 속하지 않을 수 있습니다 . 나는 그것이 나의 다른 포인트라고 생각합니다. :)
logc

@DocBrown 예, 우리는 각 고객 프로젝트마다 하나의 핵심 지점을 사용하는 법을 배웠습니다. 다른 문제가 발생했습니다. 예를 들어 이미 배포 된 고객 시스템을 '터치'하는 것을 좋아하지 않습니다. 결과적으로 각 배포 후 사용 된 코어의 몇 가지 사소한 버전 점프가 발생할 수 있습니다.
SDD64

@ SDD64 : 그것이 바로 내가 말하는 바입니다-변경 사항을 공통 코어에 즉시 통합하지 않는 것은 장기적으로 해결책이 아닙니다. 자동 및 수동 테스트를 통해 코어에 대한 더 나은 테스트 전략이 필요합니다.
Doc Brown

1
기록을 위해 각 팀마다 별도의 코어를 옹호하거나 테스트가 필요하다는 것을 부인하지는 않습니다. 그러나 앞서 언급 한 것처럼 코어 테스트와 그 구현이 동시에 변경 될 수 있습니다 . 릴리스 문자열 또는 커밋 태그로 표시된 고정 코어 만 버그 수정을 제외하고 버전 관리 정책이 올바른 경우이를 기반으로하는 프로젝트에 의존 할 수 있습니다.
logc

3

다른 사람들이 말했듯이, 우수한 단위 테스트 세트는 문제를 해결하지 못합니다. 각 팀 테스트 스위트가 통과하더라도 변경 사항을 병합하는 동안 문제가 발생합니다.

TDD와 동일합니다. 어떻게 해결할 수 있는지 모르겠습니다.

귀하의 솔루션은 비 기술적입니다. "핵심"경계를 명확하게 정의하고 "개발자 또는 설계자"인 누군가에게 "감시견"역할을 할당해야합니다. 코어에 대한 모든 변경 사항은이 워치 독을 통과해야합니다. 그는 모든 팀의 모든 산출물이 너무 많은 부수적 피해없이 합병되도록 할 책임이 있습니다.


그가 핵심의 대부분을 썼기 때문에 우리는 "감시견"을 가졌습니다. 슬프게도 그는 테스트되지 않은 대부분의 부분을 담당했습니다. 그는 YAGNI로 가장되어 반 년 전에 다른 두 사람으로 대체되었습니다. 우리는 여전히 그 '어두운 부분'을 리팩토링하기 위해 노력하고 있습니다.
SDD64

2
아이디어는 단위 테스트 스위트하는 것입니다 핵심에 있다, 코어의 일부로 모든 팀이 아닌 각 팀에 대해 별도의 테스트 스위트에서 공헌을.
Doc Brown

2
@ SDD64 : 당신은 "당신은 그것을 필요로하지 않을 것입니다 (아직)"(매우 좋은 것입니다)와 "당신은 코드를 정리 할 필요가 없습니다 (아직)"-매우 나쁜 습관입니다. IMHO와 정반대입니다.
Doc Brown

워치 독 솔루션은 실제로 매우 차선책입니다. 그것은 사람과 정치를 포함하기 때문에 시스템에 단일 실패 지점을 구축하는 것과 매우 느린 것입니다. 그렇지 않으면 TDD는 물론이 문제에 도움을 줄 수 있습니다. 각 코어 테스트는 현재 코어가 어떻게 사용되는지 고객 프로젝트 개발자에게 보여주는 예입니다. 그러나 나는 당신이 선의로 대답을했다고 생각합니다 ...
logc

@DocBrown : 알겠습니다. 이해가 다를 수도 있습니다. 그가 작성한 핵심 기능은 가장 복잡한 가능성을 만족시키기 위해 지나치게 복잡합니다. 그들 대부분은 우리는 결코 만나지 못했습니다. 복잡성으로 인해 다른 한편으로는 리팩토링 속도가 느려집니다.
SDD64

2

보다 장기적인 해결책으로 팀 간의보다 나은 적시 커뮤니케이션이 필요합니다. 핵심 기능 Y와 같이 계속 사용할 각 팀은 기능에 대해 계획된 테스트 케이스를 작성하는 데 참여해야합니다. 이 계획 자체는 두 팀 간의 기능 Y 고유의 다양한 사용 사례를 강조합니다. 기능의 작동 방식이 결정되고 테스트 사례가 구현되고 합의되면 구현 체계에 추가 변경이 필요합니다. 기능을 릴리스하는 팀은 기능을 사용하려는 팀이 아닌 테스트 케이스를 실행해야합니다. 충돌이 발생하는 작업은 팀 중 하나에서 새로운 테스트 케이스를 추가하는 것입니다. 팀원이 테스트되지 않은 기능의 새로운 측면을 생각할 때 자신의 샌드 박스를 통과 한 것으로 확인 된 테스트 케이스를 자유롭게 추가 할 수 있어야합니다. 이러한 방식으로 발생하는 유일한 충돌은 의도 수준이며 리팩토링 된 기능이 완전히 공개되기 전에 해결해야합니다.


2

모든 시스템에는 효과적인 테스트 스위트 (즉, 자동화)가 필요하지만 이러한 테스트가 효과적으로 사용되면 이러한 충돌을 현재보다 빨리 포착 할 수 있지만 근본적인 문제는 해결하지 못합니다.

이 질문은 적어도 두 가지 근본적인 문제, 즉 개별 고객의 요구 사항을 충족시키기 위해 '핵심'을 수정하는 관행과 팀이 변경 의사를 의사 소통하고 조정하지 못하는 문제를 드러냅니다. 이들 중 어느 것도 근본 원인이 아니므로이를 해결하기 전에 이것이 수행되는 이유를 이해해야합니다.

가장 먼저 결정해야 할 사항 중 하나는 개발자와 관리자가 여기에 문제가 있음을 인식하는지 여부입니다. 적어도 일부 사람들이 그렇게한다면, 그들이 그들에 대해 아무 것도 할 수 없다고 생각하거나하지 않기로 선택한 이유를 찾아야합니다. 그렇지 않은 사람들을 위해, 현재의 행동이 미래의 문제를 어떻게 만들 수 있는지 예측할 수있는 능력을 향상 시키거나이를 가능한 사람들로 대체 할 수 있습니다. 일이 어떻게 잘못되고 있는지를 아는 인력이있을 때까지는 문제를 해결할 수 없을 것입니다.

최소한 초기에는 문제를 추상적 인 용어로 분석하기 어려울 수 있으므로 문제를 일으킨 특정 사건에 초점을 맞추고 문제가 어떻게 발생했는지 확인하십시오. 관련된 사람들이 방어적일 가능성이 높으므로 실제로 일어나는 일을 찾으려면 자급 및 사후 정당화에주의해야합니다.

고객의 요구 사항이 너무 이질적이므로 공유 코어 코드를 정당화하기에는 공통점이 충분하지 않습니다. 그렇다면 실제로 여러 개의 개별 제품이 있으므로 해당 제품을 관리해야하며 제품간에 인위적인 연결을 생성하지 않아야합니다.


제품을 Java에서 RoR로 마이그레이션하기 전에 실제로 제안한대로 진행했습니다. 우리는 모든 고객을위한 Java 코어를 가지고 있었지만, 그들의 요구 사항은 언젠가는 그것을 '파산'했고 우리는 그것을 분할해야했습니다. 그 상황에서 우리는 다음과 같은 문제에 직면했습니다. 'Dude, 고객 Y에게는 훌륭한 핵심 기능이 있습니다. 코어가 호환되지 않기 때문에 고객 Z에게 이식 할 수 없습니다. ' Rails를 통해 우리는 '모든 사람을위한 하나의 핵심'정책을 추구하고 있습니다. 변경이 필요한 경우에도 여전히 급격한 변경을 제공하지만 고객은 더 이상 업데이트하지 않아도됩니다.
SDD64

TDD를 호출하는 것만으로는 충분하지 않은 것 같습니다. 따라서 핵심 제안을 나누는 것 외에도 귀하의 답변이 가장 좋습니다. 안타깝게도 핵심은 완벽하게 테스트되지는 않았지만 모든 문제를 해결할 수는 없습니다. 한 고객을 위해 새로운 핵심 기능을 추가하면 고객에게 핵심 사양 만 공유되므로 완벽하게 괜찮아 보이고 친환경적입니다. 가능한 한 모든 고객에게 일어나는 일을 알지 못합니다. 따라서 문제를 찾고 그 원인에 대해 이야기하기를 제안합니다.
SDD64

1

우리는 모두 단위 테스트가 진행된다는 것을 알고 있습니다. 그러나 우리는 이것들을 코어에 현실적으로 개조하는 것이 어렵다는 것을 알고 있습니다.

기능을 확장 할 때 유용 할 수있는 특정 기술은 기존 기능이 변경되지 않았는지 일시적으로 로컬에서 확인하는 것입니다. 이것은 다음과 같이 수행 할 수 있습니다 :

원래 의사 코드 :

def someFunction
   do original stuff
   return result
end

임시 현장 테스트 코드 :

def someFunctionNew
   new do stuff
   return result
end

def someFunctionOld
   do original stuff
   return result
end

def someFunction
   oldResult = someFunctionOld
   newResult = someFunctionNew
   check oldResult = newResult
   return newResult
end

존재하는 시스템 레벨 테스트를 통해이 버전을 실행하십시오. 모든 것이 괜찮다면, 당신은 당신이 물건을 깨지 않았 음을 알고 오래된 코드를 제거 할 수 있습니다. 당신은 과거와 결과가 일치 검사 할 때, 당신은 또한 당신이 알고 캡처의 경우에 차이를 분석하는 코드를 추가 할 수 있음을주의 해야한다 이러한 버그 수정으로 인해 의도 된 변화 다를 수 있습니다.


1

"버그가 거의 항상 예상치 못한 공격 때문에 대부분의 변화는 팀을 통해 발표되지 않은"

통신 문제 누군가? 적절한 의사 소통이 있는지 확인하기 위해 (다른 사람들이 이미 지적한 것 외에도 엄격한 테스트를 받아야 함) 어떻습니까? 사람들은 그들이 작성하는 인터페이스가 다음 릴리스에서 변경 될 것이며 그 변경 내용은 무엇입니까?
그리고 개발 중에 가능한 한 빨리 더미 인터페이스 (빈 구현으로)에 액세스하여 자체 코드 작성을 시작할 수 있도록하십시오.

모든 것이 없으면 단위 테스트는 시스템의 각 부분 사이에 문제가 있다는 마지막 단계를 지적하는 것 외에는 별다른 영향을 미치지 않습니다. 그 사실을 알고 싶지만 일찍, 아주 일찍 알고 팀이 서로 대화하고 노력을 조정하며 실제로 다른 팀이하고있는 작업에 자주 액세스 할 수 있도록하려면 (대규모가 아닌 정기적 인 커밋) 배달 몇 주 또는 몇 달, 1-2 일 후 커밋).
버그는 코드에 포함되어 있지 않으며 다른 팀의 코드에는 포함되어 있지 않습니다. 버그는 개발 프로세스에 있으며 사람들 간의 의사 소통과 협업이 부족합니다. 다른 방에 앉아 있다고해서 다른 사람과 자신을 격리시켜야한다는 의미는 아닙니다.


1

주로 의사 소통 문제 (아마도 팀 빌딩 문제 와 관련이 있음 )가 있으므로 귀하의 사례에 대한 솔루션은 개발 기술 대신 의사 소통에 중점을 두어야한다고 생각합니다.

고객 프로젝트를 시작할 때 핵심 모듈을 정지 시키거나 포크 할 수 없다는 점은 당연한 일입니다 (그렇지 않으면 단순히 핵심 모듈 업데이트를 목표로하는 비 고객 관련 프로젝트 일정을 회사에 통합해야합니다).

따라서 우리는 팀 간의 의사 소통을 개선하려는 문제에 직면 해 있습니다. 이것은 두 가지 방법으로 해결할 수 있습니다.

  • 인간과. 즉, 귀사 는 코드의 품질과 가용성을 책임지는 핵심 모듈 아키텍트 (또는 최고 경영진에게 적합한 용어) 로 회사를 지정 합니다. 이 사람은 핵심을 구체화 할 것입니다. 따라서 그녀는 모든 팀이 공유하고 팀 간의 적절한 동기화를 보장합니다. 또한, 일관성을 유지하기 위해 핵심 모듈에 적용되는 코드를 검토하는 역할을 수행해야합니다.
  • 도구와 워크 플로우. 부과함으로써 지속적인 통합을 핵심에, 당신은 핵심 코드 자체 통신 매체 할 것입니다. 이를 위해서는 먼저 자동화 된 테스트 스위트를 추가하여 약간의 노력이 필요하지만 야간 CI 보고서는 핵심 모듈의 전반적인 상태 업데이트가됩니다.

통신 프로세스로 CI에 대한 자세한 내용은 여기를 참조하십시오 .

마지막으로 회사 수준에서 팀 작업이 부족하다는 문제가 있습니다. 나는 팀 빌딩 이벤트의 열렬한 팬은 아니지만 이것이 유용한 경우처럼 보입니다. 정기적으로 개발자 차원의 회의가 있습니까? 다른 팀의 사람들을 프로젝트 회고에 초대 할 수 있습니까? 아니면 금요일 저녁 맥주를 드시나요?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.