콘텐츠로 이동

원칙

이 페이지는 Tuist의 설계와 개발의 핵심이 되는 원칙을 설명합니다. 이러한 원칙은 프로젝트와 함께 진화하며, 프로젝트 기반과 잘 부합하는 지속 가능한 성장을 보장하기 위해 마련되었습니다.

규약을 기본값으로 사용#

Tuist가 존재하는 이유 중 하나는 Xcode가 규약 측면에서 약해 확장성과 유지보수가 어려운 복잡한 프로젝트로 이어지기 때문입니다. 따라서 Tuist는 단순하고 철저하게 설계된 규약을 기본값으로 사용하는 다른 접근 방식을 취합니다. 개발자는 규약을 선택 해제할 수 있지만, 이는 자연스럽지 않은 의식적인 결정입니다.

예를 들어, 제공된 공개 인터페이스를 사용해 타겟 간 의존성을 정의하는 규약이 있습니다. 이렇게 하면 Tuist는 링크가 정상 작동하도록 올바른 구성으로 프로젝트를 생성합니다. 개발자는 빌드 설정을 통해 의존성을 정의할 수도 있지만, 이는 암시적으로 수행되는 것이므로 일부 규약 준수를 전제로 하는 tuist graph 또는 tuist cache 같은 Tuist 기능을 손상시키게 됩니다.

규약을 기본값으로 사용하는 이유는 개발자를 대신해 더 많은 결정을 내릴수록 앱 기능 구현에 더 집중할 수 있기 때문입니다. 많은 프로젝트에서 볼 수 있듯 규약이 없으면 다른 결정과 일관되지 않는 결정을 내리게 되고, 그 결과 관리하기 어려운 우발적 복잡성이 발생합니다.

매니페스트가 단일 신뢰 소스#

여러 계층의 구성과 그 사이의 계약이 있으면 이해하고 유지보수하기 어려운 프로젝트 설정이 됩니다. 일반적인 프로젝트를 잠시 생각해 보세요. 프로젝트 정의는 .xcodeproj 디렉터리에, CLI는 스크립트(예: Fastfiles)에, CI 로직은 파이프라인에 존재합니다. 이는 우리가 유지해야 하는 세 개의 계층과 그 사이의 계약입니다. 프로젝트에서 무언가를 변경한 후 일주일 뒤에 릴리스 스크립트가 깨진 것을 알게 된 경험이 얼마나 자주 있었나요?

매니페스트 파일을 단일 신뢰 소스로 삼아 이를 단순화할 수 있습니다. 이 파일들은 Tuist가 개발자가 파일을 편집하는 데 사용할 Xcode 프로젝트를 생성하는 데 필요한 정보를 제공합니다. 또한 로컬 또는 CI 환경에서 프로젝트를 빌드하기 위한 표준 명령어를 사용할 수 있게 합니다.

Tuist는 복잡성을 내부에서 처리하고, 프로젝트를 최대한 명시적으로 설명할 수 있는 단순하고 안전하며 사용하기 즐거운 인터페이스를 제공해야 합니다.

암시적 요소를 명시적으로 만들기#

Xcode는 암시적 구성을 지원합니다. 그 좋은 예로 암시적으로 정의된 의존성을 추론하는 기능이 있습니다. 암시성은 구성이 간단한 소규모 프로젝트에서는 괜찮지만, 프로젝트가 커지면 속도 저하나 이상 동작을 일으킬 수 있습니다.

Tuist는 암시적 Xcode 동작에 대해 명시적 API를 제공해야 합니다. 또한 Xcode의 암시적 정의를 지원하되, 개발자가 명시적 접근 방식을 선택하도록 장려하는 방식으로 구현해야 합니다. Xcode의 암시성과 복잡성을 지원하면 Tuist 도입이 쉬워지고, 이후 팀은 암시성을 제거하는 시간을 가질 수 있습니다.

의존성 정의가 그 좋은 예입니다. 개발자는 빌드 설정과 단계를 통해 의존성을 정의할 수 있지만, Tuist는 채택을 장려하는 우수한 API를 제공합니다.

API를 명시적으로 설계하면 Tuist는 그렇지 않으면 불가능했을 프로젝트 검사 및 최적화를 실행할 수 있습니다. 또한 의존성 그래프 표현을 내보내는 tuist graph나 모든 타겟을 바이너리로 캐시하는 tuist cache 같은 기능을 사용할 수 있게 합니다.

Tip

Xcode에서 기능을 포팅하라는 각 요청을 단순하고 명시적인 API로 개념을 단순화할 기회로 삼아야 합니다.

단순하게 유지하기#

Xcode 프로젝트를 확장할 때 주요 과제 중 하나는 Xcode가 사용자에게 많은 복잡성을 노출한다는 점에서 비롯됩니다. 이로 인해 팀의 버스 팩터가 높아져 프로젝트와 빌드 시스템이 발생시키는 오류를 이해하는 사람이 소수에 불과합니다. 팀이 소수 인원에게 의존하게 되므로 이는 바람직하지 않은 상황입니다.

Xcode는 훌륭한 도구이지만, 수년간의 개선, 새로운 플랫폼, 프로그래밍 언어들이 표면에 반영되면서 단순함을 유지하기 어려웠습니다.

Tuist는 단순함을 유지할 기회를 활용해야 합니다. 단순한 작업을 하는 것은 즐겁고 동기 부여가 되기 때문입니다. 컴파일 과정 맨 끝에서 발생하는 오류를 디버깅하거나 기기에서 앱을 실행할 수 없는 이유를 이해하는 데 시간을 보내고 싶은 사람은 없습니다. Xcode는 작업을 하위 빌드 시스템에 위임하며, 일부 경우 오류를 실행 가능한 항목으로 변환하는 작업이 매우 미흡합니다. “framework X not found” 오류를 받고 어떻게 해야 할지 몰랐던 적이 있나요? 버그의 잠재적 근본 원인을 목록으로 받을 수 있다면 어떨지 상상해 보세요.

개발자 경험에서 시작하기#

Xcode 주변의 혁신 부족, 즉 다른 프로그래밍 환경만큼 혁신이 일어나지 않는 이유 중 일부는 기존 솔루션에서 문제 분석을 시작하는 경우가 많기 때문입니다. 그 결과 오늘날 찾는 대부분의 솔루션은 동일한 아이디어와 워크플로를 중심으로 돌아갑니다. 기존 솔루션을 고려하는 것은 좋지만, 그것이 우리의 창의성을 제한해서는 안 됩니다.

Tom Preston이 이 팟캐스트에서 말했듯이 다음과 같이 생각합니다. “대부분의 일은 달성할 수 있으며, 머릿속에 있는 것은 우주의 제약 내에서 가능하다면 코드로 실현할 수 있습니다.”개발자 경험을 어떻게 만들고 싶은지 상상한다면, 그것을 실현하는 것은 시간 문제입니다. 개발자 경험에서 문제 분석을 시작하면 사용자가 사랑하게 될 솔루션으로 이어지는 독특한 관점을 얻을 수 있습니다.

모두가 따르는 방식을 따라야 한다는 유혹을 느낄 수 있습니다. 심지어 모두가 계속 불평하는 불편함을 감수해야 한다 하더라도요. 하지만 그러지 말아야 합니다. 앱 아카이빙을 어떻게 상상하나요? 코드 서명을 어떻게 만들고 싶나요? Tuist로 어떤 프로세스를 간소화할 수 있을까요? 예를 들어, Fastlane 지원 추가는 먼저 이해해야 할 문제에 대한 해결책입니다. "왜"라는 질문을 통해 문제의 근본 원인을 파악할 수 있습니다. 동기가 어디에서 오는지 좁혀지면 Tuist가 어떻게 가장 잘 도울 수 있을지 생각해 볼 수 있습니다. 해결책이 Fastlane과의 통합일 수도 있지만, 절충안을 선택하기 전에 고려할 수 있는 다른 유효한 해결책을 무시하지 않는 것이 중요합니다.

오류는 발생할 수 있으며 실제로 발생합니다#

개발자인 우리는 오류가 발생할 수 있다는 사실을 간과하려는 본능적인 유혹을 가지고 있습니다. 그 결과 이상적인 상황만 고려하여 소프트웨어를 설계하고 테스트합니다.

Swift, 그 타입 시스템, 그리고 잘 설계된 코드는 일부 오류를 예방하는 데 도움이 될 수 있지만, 통제 범위를 벗어나는 오류도 있기 때문에 모든 오류를 막을 수는 없습니다. 사용자가 항상 인터넷에 연결되어 있거나 시스템 명령어가 성공적으로 반환될 것이라고 가정할 수 없습니다. Tuist가 실행되는 환경은 우리가 통제하는 샌드박스가 아니므로, 이러한 환경이 어떻게 변화하고 Tuist에 영향을 미칠지 이해하기 위해 노력해야 합니다.

잘못 처리된 오류는 나쁜 사용자 경험으로 이어지며, 사용자는 프로젝트에 대한 신뢰를 잃을 수 있습니다. 우리는 사용자가 Tuist의 모든 부분을, 심지어 오류를 제시하는 방식까지 즐길 수 있기를 바랍니다.

사용자의 입장이 되어 오류 메시지가 무엇을 알려주길 기대할지 상상해 봐야 합니다. 프로그래밍 언어가 오류가 전달되는 통신 채널이고 사용자가 오류의 수신자라면, 오류 메시지는 대상(사용자)이 사용하는 동일한 언어로 작성되어야 합니다. 발생한 일을 알 수 있을 만큼 충분한 정보를 포함하고 관련 없는 정보는 숨겨야 합니다. 또한 사용자가 복구하기 위해 취할 수 있는 단계를 알려주어 실행 가능해야 합니다.

마지막으로 중요한 점은, 테스트 케이스가 실패 시나리오를 고려해야 한다는 것입니다. 이는 우리가 오류를 올바르게 처리하고 있는지 확인할 뿐만 아니라, 향후 개발자가 해당 로직을 손상시키는 것을 방지합니다.