1일 1커밋🌱

5 분 소요

1. 소프트웨어 엔지니어링이란?

‘소프트웨어 엔지니어링은 흐르는 시간 위에서 순간순간의 프로그래밍을 모두 합산한 것이다’

  • 프로그래밍과 소프트웨어 엔지니어링의 차이
    • 프로그래밍 : 개발
    • 소프트웨어 엔지니어링 : 개발 + 수정 + 유지보수
  • 개발과 소프트웨어 엔지니어링을 가르는 핵심은 소프트웨어의 ‘지속 가능성’이다.

2. 팀워크 이끌어내기

  • 소프트웨어 조직이 오래 지속되려면 겸손과 신뢰, 그리고 개인이 아닌 팀을 중심으로 한 존중에 뿌리를 둬야 한다.
  • 빠르게 실패하고 반복하라. 이를 위해서는 건강한 팀 문화가 갖춰져야 한다.

3. 지식 공유

  • 무언가를 시도하다가 실패해도 안전하다.
  • 지식을 공유하는 사람들을 격려하고 보상하는 제도를 만들어라.
  • 쉽게 도움을 얻을 수 있는 환경(멘토, 커뮤니티, 코드 리뷰, 표준 정보 소스, 문서화된 자료)을 구축하라.

4. 공정 사회를 위한 엔지니어링

  • 다양한 사용자층을 포용하고 조직 구성 측면에서도 다양성을 갖추어야 한다.

5. 팀 이끌기

  • 리더십, 영향력, 팀을 위한 봉사에 집중하라.
  • 가능하면 위임하라.
  • 팀이 무엇에 집중하는지, 그리고 방향과 속도에 특히 집중하라.

6. 성장하는 조직 이끌기

  • 늘 결정(트레이드오프를 찾고 반복)하고, 늘 떠나고(위임), 늘 확장(확장에 대비하여 미리 관리)하도록 노력하라.

7. 엔지니어링 생산성 측정하기

  • GSM(목표 : goal / 신호 : signal / 지표 : metric) 프레임워크
    • 목표 : 측정자가 원하는 최종 결과

      구글은 생산성을 다섯 개의 요소로 나눴다. 이를 QUANTS 라고 한다. 이 다섯 요소 사이에는 트레이드오프가 일어난다. -코드 품질(Quality of the code) -엔지니어들의 몰입도(Attention from engineers) -지적 복잡성(Intellectual complexity) -박자와 속도(Tempo and velocity) -만족도(Satisfaction)

  • 신호 : 원하는 최종 결과를 이루었는지 판단하는 방법
  • 지표 : 신호를 대변한다. 실제로 측정하는 대상이다.

8. 스타일 가이드와 규칙

  • 규칙을 관리하는 목표는 ‘좋은’ 행동을 장려하고 ‘나쁜’ 행동을 억제하기 위함이다.
  • 상황이 바뀌면 규칙도 달라져야 하기 때문에 규칙이 만들어진 근거 데이터를 알고 있어야 한다.
  • 모든 것을 규칙으로 강제해서는 안된다.
  • 일관성이 핵심이다.
  • 가능한 한 규칙이 자동으로 적용되도록 해야 한다.

9. 코드 리뷰

  • 코드 리뷰를 통해 코드베이서 전반의 정확성, 이해 용이성, 일관성 보장, 지식을 조직 전체에 공유하는 등 이점이 많다.
  • 정적 검사 같은 문제는 가능한 한 자동화하여 더 중요한 문제에 집중하게 하라.

10. 문서자료

  • 문서자료 변경도 기존 개발자 워크플로에 통합되어야 한다.
  • 하나의 문서는 하나의 목적에 집중해야 한다.
  • 문서자료는 자신이 아니라 독자를 위해 써야한다.

11. 테스트 개요

  • 자동 테스트는 실수를 빠르게 잡아주므로 안심하고 소프트웨어를 변경할 수 있게 해준다.
  • 테스트 커버리지를 건실하게 유지하려면 균형 잡힌 테스트 스위트가 필요하다.

12. 단위 테스트

  • 변하지 않는 테스트를 만들기 위해 노력하라.
  • 공개 API를 통해 테스트하라.
  • 상호작용이 아닌 상태를 테스트하라.
  • 테스트를 완전하고 명확하게 만들라.
  • 메서드가 아닌 행위를 테스트하라.
  • 행위가 부각되게끔 테스트를 구성하라.
  • 테스트 이름은 검사하는 행위가 잘 드러나게 지어라.
  • 테스트에 로직을 넣지 마라.
  • 실패 메시지를 명확하게 작성하라.
  • 테스트들이 코드를 공유할 때는 DRY(Don’t Repeat Yourself : 반복하지 말라)보다 DAMP(Descriptive And Meaningful Phrase : 서술적이고 의미 있는 문구)를 우선하라.

13. 테스트 대역

  • 테스트 대역보다는 되도록 실제 구현을 사용해야 한다.
  • 테스트에서 실제 구현을 사용할 수 없을 때는 가짜 객체가 최선일 때가 많다.
  • 스텁을 사용하면 테스트가 불명확해지고 깨지기 쉽다.
  • 상호작용 테스트는 되도록 피하는게 좋다. 상호작용 테스트는 대상 시스템의 상세 구현 방식을 노출하기 때문에 테스트를 깨지기 쉽게 만든다.

    가짜 객체 : 제품 코드로는 적합하지 않지만 실제 구현과 비슷하게 동작하도록 가볍게 구현한 대역 ex) 인메모리 데이터베이스 스텁 : 원래는 없던 행위를 부여하는 과정을 말한다. ex) 대상 함수가 반환할 값을 지정한다고 하면, 이를 ‘반환값을 뭉갠다(스텁한다)’라고 한다.

14. 더 큰 테스트

  • 더 큰 테스트가 존재하는 이유
    • 충실성 : 테스트가 대상의 실제 행위를 얼마나 충실하게 반영했느냐를 나타내는 속성 - 단위 테스트가 손 대기 어려운 영역
      1. 부정확한 테스트 대역
      2. 설정 문제
      3. 과부하 시 나타나는 문제
      4. 예기치 못한 동작, 입력, 부작용
      5. 창발적 행위와 진공 효과(전혀 예기치 않은 새로운 행동 양식이 갑자기 나타나는 것)
  • 큰 테스트의 구조
    1. 테스트 대상 시스템 확보
2. 필요한 테스트 데이터 준비 3. 대상 시스템을 이용해 동작 수행 4. 행위 검증

15. 폐기

  • 시스템을 원래 설계 의도와 다르게 사용하는 사용자가 많기 때문에 제거하는 일이 아예 처음부터 만들기보다 어려울 때도 많다.
  • 폐기 비용을 생각하면 새로운 시스템으로 교체하기보다 기존 시스템을 개선하는 편이 일반적으로 더 저렴하다.

16. 버전 관리와 브랜치 관리

  • 트렁크 기반으로 개발하는 조직일 수록 성과가 높다 : https://code-masterjung.tistory.com/73
  • 원-버전 규칙(의존성을 새로 추가할 때 선택할 수 있는 버전을 제한한다)은 조직의 효율에 큰 영향을 준다.
  • 장수 브랜치는 금지해라.
  • 구글이 이용하는 코드 브라우징 및 검색 도구

18. 빌드 시스템과 빌드 철학

  • 아티팩트 중심으로 구성된 빌드 시스템이 태스크 중심 빌드 시스템보다 확장성과 안정성 모두 뛰어나다.
  • 아티팩트와 의존성을 정의할 때 모듈을 작게 나누는 것이 유리하다. 작은 모듈들이 병렬 빌드와 증분 빌드의 이점을 더 잘 활용한다.
  • 외부 의존성의 버전도 명확하게 버전 관리해야 한다.

19. Critique : 구글의 코드 리뷰 도구

  • 구글이 이용하는 코드 리뷰 도구

20. 정적 분석

  • 정적 분석 : ‘프로그램을 실행하지 않은 채로’ 소스 코드를 분석하여 버그와 안티패턴 등의 잠재적인 문제를 찾아내는 것.
  • 정적 분석(코드 리뷰, 컴파일러 검사, 코드 커밋 게이트키핑, IDE, 코드 브라우징 시점)을 개발자 워크플로에 반드시 포함하자.

21. 의존성 관리

  • 의존성 관리보다는 되도록 버전 관리가 되도록 하자. 더 많은 코드를 조직 내로 가져와 투명성과 통제력을 높히면 문제가 단순해진다.
  • 의존성을 임포트할 때 장기 지원 비용까지 고려해서 신중하게 결정해야 한다.
  • 의존성 제공자가 제시하는 내용에는 지금 당장 뿐 아니라 미래에 대한 약속도 명확하게 포함되어야 한다.
  • 최소 버전 선택 전략을 사용하라.

22. 대규모 변경

  • LSC(large-scale change) 프로세스를 통해 기술적 결정들을 다시 생각해 볼 수 있게 해준다. 한 번 결정하면 되돌릴 수 없었던 설계를 후에 변경할 수 있게 해준다.
  • 구글에서 수행하는 LSC의 대다수는 기능은 거의 변경하지 않는다. 주로 명확성, 최적화, 미래 호환성 개선이 목표이다. 하지만 행위가 달라지지 않는 리팩터링 류의 변경만이 LSC의 전부는 아니다.
  • LSC에 성공하려면 LSC를 습관처럼 진행해야 한다.

23. 지속적 통합

  • CI는 빠른 피드백 루프를 이용하도록 유도하여 버그 비용을 최소로 줄여준다. 코드 또는 다른 변경을 테스트 시나리오에 통합하고 결과를 관찰하기까지가 하나의 피드백 루프이다.
  • 빠르고 더 안정적인 테스트는 프리서브밋 단계에서, 느리고 덜 결정적인 테스트는 포스트서브밋 단계에서 실행하도록 최적화해야 한다.

24. 지속적 배포

  • 속도는 팀 스포츠이다 : 거대한 코드를 함께 개발하는 팀이 빠르게 굴러가려면 아키텍처를 모듈화하고 지속적으로 통합해야 한다.
  • 변경은 격리해 평가해야 한다 : 문제를 조기에 격리할 수 있도록 기능별로 플래그 카드를 세워두어라.
  • 현실을 직시하라 : 기기가 다양하고 사용자 기반이 넓다면 단계적 출시로 대응하라.
  • 쓰일 기능만 배포하라 : 기능별로 출시 비용과 창출 가치를 모니터링하여, 고객이 여전히 이용하며 충분한 가치를 제공하고 있는지 확인하라.
  • 원점으로 회귀하라 : 지속적 통합과 지속적 배포를 적용하여 모든 변경에 대한 판단을 더 빠르게 더 많은 데이터에 기초해 내려라.
  • 빠를 수록 안전하다 : 적게 수정하여 빨리 자주 배포하면 각 릴리스의 위험이 줄고 시장 변화에 적시에 대응할 수 있다.

25. 서비스형 컴퓨트

  • 조직 전체가 하나의 인프라를 공유하면 관리와 자원 활용 효율을 상당히 개선할 수 있고, 공통 인프라 위에서 모두가 사용하는 도구를 개발할 수 있다.
  • 이런 아키텍처를 구축하려면 서로 다른 작업이 같은 물리(혹은 가상) 머신을 공유할 수 있게 해주는 컨테이너가 반드시 필요하다. 머신을 공유한다는 건 곧 자원을 효율적으로 이용한다는 뜻이다.
  • 또한 컨테이너는 애플리케이션과 운영체제 사이에 추상 계층을 만들어줘서 미래에도 애플리케이션을 탄력적으로 운용할 수 있게 해준다.
  • 컨테이너 기반 아키텍처를 십분 활용하려면 애플리케이션을 가축처럼 다뤄도 되게끔 설계해야 한다. 애플리케이션을 쉽게 자동으로 교체할 수 있는 노드로 이루어지게끔 설계하면 수천 개의 인스턴스로 확장할 수 있다.
  • VM이나 물리 머신을 직접 관리하는 ‘반려동물’ 모델, 복제된 컨테이너라는 ‘가축’ 모델, 한층 더 추상화된 서버리스 모델이 있는데 트레이드 오프를 보고 신중하게 조직에 맞는 선택지를 골라야 한다.

카테고리:

업데이트:

댓글남기기