window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster가 이미 존재합니다') } else { w.LeadBooster = { q: [], on: 함수 (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: 함수 (n) { this.q.push({ t: 't', n: n }) }, } } })() 잘못된 코딩 관행으로 프로젝트를 죽이지 않는 방법은 무엇일까요? - The Codest
The Codest
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 산업 분야
    • 핀테크 및 뱅킹
    • E-commerce
    • 애드테크
    • 헬스 테크
    • 제조
    • 물류
    • 자동차
    • IOT
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
뒤로 화살표 뒤로 가기
2021-05-06
소프트웨어 개발

잘못된 코딩 관행으로 프로젝트를 죽이지 않는 방법은 무엇인가요?

The Codest

바르토슈 슬리즈

Software Engineer

경력을 시작하는 많은 프로그래머는 변수, 함수, 파일 및 기타 구성 요소의 이름을 지정하는 주제를 그다지 중요하지 않다고 생각합니다. 그 결과 알고리즘이 빠르게 실행되고 원하는 효과를 내면서도 가독성이 떨어지는 등 설계 로직이 올바른 경우가 많습니다. 이 글에서는 다양한 코드 요소의 이름을 지정할 때 참고해야 할 사항과 극단적인 이름을 지정하지 않는 방법에 대해 간략하게 설명하겠습니다.

네이밍 단계를 소홀히 하면 프로젝트 개발이 (경우에 따라서는 엄청나게) 길어지는 이유는 무엇일까요?

귀하와 귀하의 팀 를 인수하고 있습니다. 코드 다른 프로그래머로부터. 다른 프로그래머의 프로젝트 는 애정을 쏟지 않고 개발되었지만, 모든 요소가 훨씬 더 나은 방식으로 작성될 수 있었을 것입니다.

아키텍처와 관련하여 코드 상속의 경우 거의 항상 코드를 받은 프로그래머의 증오와 분노를 유발합니다. 때로는 죽어가는(또는 사라진) 기술을 사용하거나, 때로는 개발 초기에 애플리케이션에 대한 잘못된 사고 방식, 때로는 단순히 담당 프로그래머의 지식 부족으로 인해 발생하기도 합니다.

어쨌든 프로젝트 시간이 지날수록 프로그래머가 아키텍처와 기술에 열광하는 지점에 도달할 수 있습니다. 결국 모든 애플리케이션은 시간이 지나면 일부 부분을 다시 작성하거나 특정 부분을 변경해야 하는 것은 당연한 일입니다. 그러나 프로그래머의 머리를 하얗게 만드는 문제는 상속받은 코드를 읽고 이해하는 데 어려움이 있다는 것입니다.

특히 변수가 의미 없는 단일 문자로 명명되고 함수가 애플리케이션의 나머지 부분과 전혀 일관성이 없이 갑자기 창의력을 발휘하는 극단적인 경우에는 프로그래머가 미쳐버릴 수 있습니다. 이러한 경우 올바른 이름 지정으로 빠르고 효율적으로 실행할 수 있는 코드 분석은 예를 들어 함수 결과를 생성하는 알고리즘에 대한 추가 분석이 필요합니다. 이러한 분석은 눈에 잘 띄지 않지만 엄청난 시간을 낭비하게 됩니다.

애플리케이션의 다른 부분에 새로운 기능을 구현하면 시간이 지나면 의도가 명확하지 않아 다시 코드로 돌아가 분석해야 하는 악몽을 겪게 되고, 그 동작을 이해하려고 했던 이전의 시간은 더 이상 목적이 무엇인지 기억나지 않아 낭비되는 경우가 많습니다.

따라서 우리는 애플리케이션을 지배하고 개발의 모든 참여자를 천천히 잡아먹는 무질서의 토네이도에 빨려 들어가게 됩니다. 프로그래머는 프로젝트를 싫어하고, 프로젝트 관리자는 개발 시간이 계속 늘어나는 이유를 설명하는 것을 싫어하며, 고객은 계획대로 진행되는 것이 없기 때문에 신뢰를 잃고 화를 냅니다.

어떻게 피할 수 있나요?

현실을 직시하자 - 건너뛸 수 없는 것도 있습니다. 프로젝트 초기에 특정 기술을 선택했다면 시간이 지남에 따라 지원이 중단되거나 몇 년 전의 기술에 능통한 프로그래머가 점점 줄어들어 서서히 구식이 될 수 있다는 사실을 인지해야 합니다. 업데이트되는 일부 라이브러리의 경우 코드에 다소 많은 변경이 필요하기 때문에 종속성의 소용돌이에 휘말려 더 큰 어려움을 겪을 수 있습니다.

물론 기술은 점점 더 오래되고 있지만 이와 관련된 프로젝트의 개발 시간을 확실히 늦추는 요소는 대부분 추악한 코드입니다. 물론 여기에서 Robert C. Martin의 책을 언급해야합니다. 이 책은 프로그래머를위한 성경으로, 저자는 완벽을 추구하는 코드를 만들기 위해 따라야 할 많은 모범 사례와 원칙을 제시합니다.

  1. 변수 이름을 지을 때 가장 기본적인 것은 변수의 의도를 명확하고 간단하게 전달하는 것입니다. 아주 간단하게 들리지만 많은 사람들이 이를 간과하거나 무시하는 경우가 있습니다. 좋은 이름은 변수가 정확히 무엇을 저장해야 하는지 또는 함수가 무엇을 수행해야 하는지를 명시합니다. 너무 포괄적으로 이름을 지어도 안 되지만, 그렇다고 너무 길어서 읽기만 해도 두뇌에 상당한 부담을 주는 긴 이름이 되어서도 안 됩니다. 양질의 코드를 어느 정도 시간이 지나면 무의식적으로 함수에 이름을 붙이고 데이터를 전달할 때 어떤 의도로 함수를 호출했는지, 함수를 호출했을 때 예상되는 결과가 무엇인지에 대한 환상을 남기지 않도록 무의식적으로 배열할 수 있는 몰입 효과를 경험하게 됩니다.
  2. 또한 JavaScript는 무엇보다도 코드를 과도하게 최적화하려는 시도이며, 이로 인해 많은 경우 코드를 읽을 수 없게 됩니다. 일부 알고리즘은 특별한 주의가 필요하며, 이는 코드의 의도가 조금 더 복잡할 수 있다는 사실을 반영하는 경우가 많습니다. 그럼에도 불구하고 과도한 최적화가 필요한 경우는 극히 드물거나 적어도 코드가 더럽혀진 경우입니다. 많은 언어 관련 최적화는 약간 낮은 수준의 추상화에서 이루어지며, 예를 들어 V8 엔진은 충분한 반복을 통해 루프 속도를 크게 높일 수 있다는 점을 기억하는 것이 중요합니다. 강조해야 할 것은 우리가 21세기에 살고 있고 아폴로 13호 임무를 위한 프로그램을 작성하지 않는다는 사실입니다. 우리는 자원이라는 주제에서 훨씬 더 많은 기동의 여지가 있습니다. 자원은 (가급적 합리적인 방식으로 :>) 사용하기 위해 존재합니다.
  3. 때로는 코드를 여러 부분으로 나누면 많은 것을 얻을 수 있습니다. 작업이 데이터의 특정 수정을 담당하는 작업을 수행하는 것을 목적으로 하는 체인을 형성할 때 길을 잃기 쉽습니다. 따라서 간단한 방법으로 모든 것을 하나의 문자열로 수행하는 대신 특정 작업을 담당하는 코드의 개별 부분을 개별 요소로 나눌 수 있습니다. 이렇게 하면 개별 작업의 의도가 명확해질 뿐만 아니라 한 가지 작업만 담당하는 코드 조각을 테스트할 수 있고 쉽게 재사용할 수 있습니다.

몇 가지 실제 사례

위의 일부 문장을 가장 정확하게 표현하는 방법은 실제로 어떻게 작동하는지 보여주는 것이라고 생각합니다. 이 단락에서는 어느 정도 좋은 코드 관행으로 바꿀 수 있는 몇 가지 나쁜 코드 관행을 간략하게 설명하려고 합니다. 어떤 순간에 코드의 가독성을 방해하는 요소와 이를 방지하는 방법을 지적하겠습니다.

한 글자 변수의 폐해

안타깝게도 대학에서도 흔히 볼 수 있는 끔찍한 관행은 한 글자로 변수의 이름을 짓는 것입니다. 변수의 목적을 파악하기 위해 불필요한 고민을 하지 않고 여러 글자를 사용하는 대신 한 글자(예: i, j, k)만 사용하는 것이 때로는 매우 편리한 해결책이라는 데 동의하지 않기는 어렵습니다.

역설적이게도 이러한 변수에 대한 일부 정의에는 훨씬 더 긴 설명이 붙어 있어 작성자가 염두에 둔 것이 무엇인지 알 수 있습니다.

여기서 좋은 예는 열과 행의 교차점에 해당 값이 포함된 2차원 배열에 대한 반복을 표현하는 것입니다.

const array = [[0, 1, 2], [3, 4, 5], [6, 7, 8]];

// 꽤 나쁘다
for (let i = 0; i < array[i]; i++) {
  for (let j = 0; j < array[i][j]; j++) { {
    // 여기에 내용이 있지만, i와 j가 사용될 때마다 다시 돌아가서 그들이 무엇에 사용되는지 분석해야 합니다.
  }
}

// 여전히 나쁘지만 재밌습니다.
let i; // 행
let j; // 열

for (i = 0; i < array[i]; i++) {
  for (j = 0; j < array[i][j]; j++) { {
    // 여기에 내용이 있지만 i와 j가 사용될 때마다 돌아가서 그들이 무엇에 사용되는지 주석을 확인해야합니다.
  }
}

// 훨씬 낫습니다.
const rowCount = array.length;

for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
  const row = array[rowIndex];
  const columnCount = row.length;

  for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
    const column = row[columnIndex];

    // 뭐가 뭔지 의심스러운 사람 있나요?
  }
}

교묘한 과잉 최적화

어느 화창한 날, 저는 어떤 사람이 작성한 매우 정교한 코드를 발견했습니다. 소프트웨어 엔지니어. 이 엔지니어는 사용자 권한을 특정 작업을 지정하는 문자열로 전송하면 몇 가지 비트 수준 트릭을 사용하여 크게 최적화할 수 있다는 사실을 알아냈습니다.

아마도 이러한 솔루션은 대상이 Commodore 64라면 괜찮을 것이지만 이 코드의 목적은 JS로 작성된 간단한 웹 애플리케이션이었습니다. 이 단점을 극복할 때가 왔습니다:
사용자가 전체 시스템에서 콘텐츠를 수정할 수 있는 옵션이 작성, 읽기, 업데이트, 삭제의 네 가지뿐이라고 가정해 보겠습니다. 이러한 권한을 상태 또는 배열이 있는 객체의 키로 JSON 형식으로 전송하는 것은 매우 자연스러운 일입니다.

하지만 영리한 엔지니어는 숫자 4가 이진 표현에서 마법 같은 값이라는 것을 알아채고 다음과 같이 알아냈습니다:

나쁜 코드 습관

전체 기능 표에는 16개의 행이 있지만, 이러한 권한을 만드는 아이디어를 전달하기 위해 4개만 나열했습니다. 권한을 읽는 방법은 다음과 같습니다:

const user = { 권한: 11 };

const canCreate = Boolean(user.permissions & 8); // 참
const canRead = Boolean(user.permissions & 4); // false
const canUpdate = Boolean(user.permissions & 2); // 참
const canDelete = Boolean(user.permissions & 1); // 참

위에 표시된 내용은 웹 어셈블리 코드. 이러한 최적화는 특정 작업에 시간이나 메모리(또는 둘 다)가 거의 필요하지 않은 시스템에서 흔히 볼 수 있는 일입니다. 반면에 웹 애플리케이션은 이러한 과도한 최적화가 전혀 의미가 없는 곳이 아닙니다. 일반화하고 싶지는 않지만 프런트엔드 개발자의 작업에서 비트 추상화 수준에 이르는 복잡한 작업은 거의 수행되지 않습니다.

단순히 읽을 수 없으며 이러한 코드를 분석 할 수있는 프로그래머는이 솔루션이 어떤 보이지 않는 이점이 있는지, 그리고 손상 될 수있는 것이 무엇인지 궁금해 할 것입니다. 개발 팀 보다 합리적인 솔루션으로 다시 작성하려고 합니다.

또한 권한을 일반 개체로 보내면 프로그래머가 1-2 초 안에 의도를 읽을 수 있지만 처음부터이 모든 것을 분석하는 데 최소 몇 분이 걸릴 것이라고 생각합니다. 프로젝트에는 여러 프로그래머가있을 것이며, 각 프로그래머는이 코드를 접해야 할 것입니다. 시간이 지나면 어떤 마법이 일어나고 있는지 잊어 버릴 것이기 때문에 여러 번 분석해야 할 것입니다. 그 몇 바이트를 절약할 가치가 있을까요? 제 생각에는 그렇지 않습니다.

나누고 정복하기

웹 개발 가 빠르게 성장하고 있으며 이와 관련하여 곧 변화가 있을 것이라는 징후는 없습니다. 최근 프론트엔드 개발자의 책임이 크게 증가하여 사용자 인터페이스에서 데이터 표시를 담당하는 로직의 일부를 맡게 되었음을 인정하지 않을 수 없습니다.

때로는 이 로직이 간단하고 API에서 제공하는 객체의 구조가 간단하고 읽기 쉬운 경우도 있습니다. 그러나 때로는 페이지의 다른 위치에 맞게 조정하기 위해 다양한 유형의 매핑, 정렬 및 기타 작업이 필요합니다. 바로 이 지점이 우리가 쉽게 늪에 빠질 수 있는 곳입니다.

저는 수행하던 연산의 데이터를 거의 읽을 수 없게 만든 적이 여러 번 있었습니다. 배열 메서드와 적절한 변수 이름을 올바르게 사용했음에도 불구하고, 어떤 시점에서는 일련의 연산으로 인해 제가 달성하고자 하는 목적의 맥락을 거의 잃어버릴 뻔했습니다. 또한 이러한 연산 중 일부는 다른 곳에서 사용해야 하는 경우도 있었고, 때로는 쓰기 테스트가 필요할 정도로 전역적이거나 정교한 경우도 있었습니다.

const devices = [
  { id: '001', 버전: 1, 소유자: { 위치: '텍사스', 나이: 21 } }. },
  { id: '002', 버전: 2, 소유자: { 위치: '텍사스', 나이: 27 } }, { id: '002', 버전: 2, 소유자: { 위치: '텍사스', 나이: 27 } }. },
  { id: '003', 버전: 3, 소유자: { 위치: '애리조나', 나이: 27 } }. },
  { id: '004', 버전: 2, 소유자: { 위치: '시카고', 나이: 24 } }. },
  { id: '005', 버전: 2, 소유자: { 위치: '애리조나', 나이: 19 } }. },
  { id: '006', 버전: 3, 소유자: { 위치: '텍사스', 나이: 42 } }. },
];

// 꽤 복잡
(() => {
  const locationAgeMap = devices
    .map(device => device.owner)
    .reduce((map, item) => {
      if (!map[item.location]) { {
        map[item.location] = item.age;
      } else {
        map[item.location] += item.age;
      }

      return map;
    }, {});

  const locationLegalAgeOwnersMap = devices
    .map(device => device.owner)
    .filter(owner => owner.age >= 21)
    .reduce((map, item) => {
      if (!map[item.location]) { {
        map[item.location] = [item];
      } else {
        map[item.location].push(item);
      }

      반환 지도;
    }, {});

  console.log({ locationAgeMap, locationLegalAgeOwnersMap });
})();

// 여전히 복잡하지만 더 간결해졌습니다.
(() => {
  const locationOwnersMap = devices
  .map(device => device.owner)
  .reduce((map, item) => {
    if (!map[item.location]) { {
      map[item.location] = [item];
    } else {
      map[item.location].push(item);
    }

    반환 지도;
  }, {});

  const locationAgeMap = Object.fromEntries(
    Object.entries(locationOwnersMap).map(([location, owners]) => {
      const ownersAge = owners.map(소유자 => 소유자.나이).reduce((a, b) => a + b);

      반환 [위치, 소유자 연령];
    })
  );

  const locationLegalAgeOwnersMap = Object.fromEntries(
    Object.entries(locationOwnersMap).map(([location, owners]) => {
      const filteredOwners = owners.filter(owner => owner.age >= 21);

      반환 [위치, 필터링된 소유자];
    }).filter(([_location, owners]) => {
      반환 소유자.길이 > 0;
    })
  );

  console.log({ locationAgeMap, locationLegalAgeOwnersMap });
})();

알아요, 알아요 - 제가 전달하고자 하는 바를 쉽게 설명하는 사소한 코드가 아닙니다. 또한 두 예제의 계산 복잡성이 약간 다르다는 것도 알고 있지만, 99%의 경우에는 걱정할 필요가 없습니다. 두 알고리즘의 차이점은 둘 다 위치와 디바이스 소유자의 지도를 준비한다는 점에서 간단합니다.

첫 번째 알고리즘은 이 지도를 두 번 준비하는 반면, 두 번째 알고리즘은 한 번만 준비합니다. 두 번째 알고리즘이 더 이식성이 뛰어나다는 것을 보여주는 가장 간단한 예는 첫 번째 알고리즘에서 특정 위치나 기타 비즈니스 로직이라고 하는 이상한 것들을 제외하는 등 이 맵을 만드는 로직을 변경해야 한다는 사실에 있습니다. 두 번째 알고리즘의 경우 지도를 가져오는 방법만 수정하고 이후 줄에서 발생하는 나머지 데이터 수정은 모두 변경하지 않습니다. 첫 번째 알고리즘의 경우 지도를 준비할 때마다 수정해야 합니다.

실제로는 전체 애플리케이션에서 특정 데이터 모델을 변환하거나 리팩터링해야 하는 경우가 많이 있습니다.

다양한 비즈니스 변화를 따라잡지 않는 가장 좋은 방법은 상당히 일반적인 방식으로 관심 있는 정보를 추출할 수 있는 글로벌 도구를 준비하는 것입니다. 최적화 해제에 따른 2~3밀리초의 손실을 감수하더라도 말이죠.

요약

프로그래머는 다른 직업과 마찬가지로 매일 새로운 것을 배우고 종종 많은 실수를 저지르는 직업입니다. 가장 중요한 것은 이러한 실수로부터 배우고 더 나은 사람이 되어 앞으로는 이러한 실수를 반복하지 않는 것입니다. 우리가 하는 일이 항상 완벽할 것이라는 신화를 믿어서는 안 됩니다. 그러나 다른 사람들의 경험을 바탕으로 그에 따라 결함을 줄일 수는 있습니다.

이 글을 읽으면서 최소한 다음과 같은 문제를 피하는 데 도움이 되길 바랍니다. 잘못된 코딩 관행 제가 업무에서 경험한 사례를 소개합니다. 모범 코드 관행에 관한 질문이 있는 경우 다음 연락처로 문의하세요. The Codest 승무원 를 통해 궁금한 점을 상담하세요.

자세히 읽어보세요:

NextJS의 데이터 가져오기 전략

웹 앱 보안 - XSS 취약점

웹 앱 보안. Target="_blank" 취약점

*타이틀 그래픽은 speednet.pl에서 가져온 것입니다.

관련 문서

소프트웨어 개발

미래 지향적인 웹 앱 구축: The Codest의 전문가 팀이 제공하는 인사이트

The Codest가 최첨단 기술로 확장 가능한 대화형 웹 애플리케이션을 제작하고 모든 플랫폼에서 원활한 사용자 경험을 제공하는 데 탁월한 성능을 발휘하는 방법을 알아보세요. Adobe의 전문성이 어떻게 디지털 혁신과 비즈니스를 촉진하는지 알아보세요...

최신
소프트웨어 개발

라트비아에 본사를 둔 10대 소프트웨어 개발 기업

최신 기사에서 라트비아 최고의 소프트웨어 개발 기업과 그들의 혁신적인 솔루션에 대해 알아보세요. 이러한 기술 리더들이 어떻게 귀사의 비즈니스를 향상시키는 데 도움을 줄 수 있는지 알아보세요.

thecodest
엔터프라이즈 및 스케일업 솔루션

Java 소프트웨어 개발 필수 사항: 성공적인 아웃소싱을 위한 가이드

The Codest로 효율성을 높이고 전문 지식을 활용하며 프로젝트 성공을 이끌 수 있는 성공적인 outsourcing Java 소프트웨어 개발에 대한 이 필수 가이드를 살펴보세요.

thecodest
소프트웨어 개발

폴란드 아웃소싱을 위한 최고의 가이드

폴란드에서 outsourcing가 급증한 것은 경제, 교육, 기술 발전으로 인한 IT 성장과 비즈니스 친화적인 환경이 조성된 덕분입니다.

더코데스트
엔터프라이즈 및 스케일업 솔루션

IT 감사 도구 및 기술에 대한 완벽한 가이드

IT 감사는 안전하고 효율적이며 규정을 준수하는 시스템을 보장합니다. 전체 기사를 읽고 그 중요성에 대해 자세히 알아보세요.

The Codest
야쿱 야쿠보비치 CTO & 공동 설립자

지식창고를 구독하고 IT 분야의 전문 지식을 최신 상태로 유지하세요.

    회사 소개

    The Codest - 폴란드에 기술 허브를 둔 국제 소프트웨어 개발 회사입니다.

    영국 - 본사

    • 사무실 303B, 182-184 하이 스트리트 노스 E6 2JA
      영국 런던

    폴란드 - 현지 기술 허브

    • 파브리츠나 오피스 파크, 알레야
      포코주 18, 31-564 크라쿠프
    • 뇌 대사관, 콘스트럭터스카
      11, 02-673 바르샤바, 폴란드

      The Codest

    • 홈
    • 회사 소개
    • 서비스
    • Case Studies
    • 방법 알아보기
    • 채용 정보
    • 사전

      서비스

    • IT 자문
    • 소프트웨어 개발
    • 백엔드 개발
    • 프론트엔드 개발
    • Staff Augmentation
    • 백엔드 개발자
    • 클라우드 엔지니어
    • 데이터 엔지니어
    • 기타
    • QA 엔지니어

      리소스

    • 외부 소프트웨어 개발 파트너와의 협력에 대한 사실과 오해
    • 미국에서 유럽으로: 미국 스타트업이 유럽으로 이전을 결정하는 이유
    • 테크 오프쇼어 개발 허브 비교: 테크 오프쇼어 유럽(폴란드), 아세안(필리핀), 유라시아(터키)
    • CTO와 CIO의 주요 과제는 무엇인가요?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • 웹사이트 이용 약관

    저작권 © 2025 by The Codest. 모든 권리 보유.

    ko_KRKorean
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese es_ESSpanish nl_NLDutch etEstonian elGreek ko_KRKorean