Github의 Black lives matter

심심해서 Github 공식 블로그를 구경하다가 10월을 기점으로 Github에서 Repository를 생성할 때 Default 브랜치명이 master에서 main으로 바뀐다는 글을 보았다. (github.blog/changelog/2020-10-01-the-default-branch-for-newly-created-repositories-is-now-main/)

Default 브랜치명을 굳이? 왜? 바꿀까 싶어 찾아보았다. 최근 미국에서는 Black lives matter 운동이 큰 이슈가 되고 있다. 이러한 움직임의 연장으로 미국의 IT업계에는 이전부터 논란이 된 master/slave, blacklist/whitelist 와 같은 언어적인 문제들을 개선하려는 움직임이 많아지고 있다고 한다. 그 중 Github도 이러한 사회의 흐름에 발맞춰 움직인 것 같다.

이미 존재하는 Repository의 Default branch를 임의로 모두 바꾸게 되면 사용자들에게 큰 파장을 일으킬 수 있다. 이러한 문제가 발생하지 않도록 우선 신규 Repository 생성시에만 Default 브랜치명이 main으로 생성되고, 기존 Repository는 연말까지 변경을 지원 할 예정이라고 한다.(github.com/github/renaming#later-this-year-seamless-move-for-existing-repositories-)



실제 사용에 어떤 영향을 미칠까?

  • 삭제한 master 브랜치의 url을 main 브랜치로 redirect 지원
    eg) github.com/user_name/repository_name/blob/master/README.md -> github.com/user_name/repository_name/blob/main/README.md
  • Github 페이지를 사용할 때 gh-pages 만 사용할 수 있었는데 이러한 제한이 없어짐
  • user, organization, enterprize 단위로 Repository 생성시 자동 생성되는 Default branch 이름 설정이 가능해짐 



기존에 생성한 Repository의 Default branch를 변경하려면?

Step 1 - git branch 명령어 중 "-m / -M" 옵션을 사용하여 master 브랜치를 main 브랜치로 rename하고 remote 저장소에 push

$ git branch -help
usage: git branch [<options>] [-r | -a] [--merged | --no-merged]
   or: git branch [<options>] [-l] [-f] <branch-name> [<start-point>]
   or: git branch [<options>] [-r] (-d | -D) <branch-name>...
   or: git branch [<options>] (-m | -M) [<old-branch>] <new-branch>
   or: git branch [<options>] (-c | -C) [<old-branch>] <new-branch>
   or: git branch [<options>] [-r | -a] [--points-at]
   or: git branch [<options>] [-r | -a] [--format]

$ git branch -m master main
$ git push -u origin main

Step 2 - Github의 Repository 설정 변경

Step 3 - master 브랜치 삭제

사용하지 않는 브랜치는 지워주는게 좋다. 

github.com/user_name/repository_name/branches 에서 master 브랜치를 지워준다.



main이 아닌 다른 Default 브랜치명을 사용해야 한다면?

그렇다고 모든 신규 repository의 default 브랜치명을 main으로 강제하는 것은 아니다.
master 브랜치, 혹은 다른 이름의 default 브랜치를 계속해서 사용해야 한다면 github.com/settings/repositories 에서 아래의 빨간 박스가 되어 있는 main 대신 master 혹은 원하는 default 브랜치명으로 업데이트하면 새로운 repository를 생성해도 main으로 default 브랜치를 생성하지 않는다.



사담

미국의 IT업계에서 master/slave, blacklist/whitelist 등 일반적으로 사용되는 언어에 대해서 이미 논란이 있어 왔다는 것을 처음 알았다🤭
조지 플로이드 사건 이후 종종 기술 검색을 하거나 웹을 떠돌다보면 Reddit이 오렌지 로고에서 검정 로고로 변경한 것, 어떤 기술의 메인페이지에 Black lives matter 해시태그가 추가된 이미지가 있는다던지 등의 모습들이 보였는데 실제 내가 사용하는 영역까지 영향을 받는 것은 처음이라 인상깊었다.
다양한 인종이 있는 만큼 한국에서는 아무생각 없이 지나칠 부분에도 다양한 논의가 있고, 이를 개선한다는 것은 매우 좋은 것 같다. Black 뿐만 아니라 Asian에 대한 차별까지 관심이 확장되면 좋겠다🙃



참고

github.com/github/renaming

www.sedaily.com/NewsView/1Z567TI23H

반응형

목차

  1. Write Ahead Log (WAL)
  2. StoreFile (HFile)
  3. 변경 사항 복구

개요

HBase를 매일 이리저리 사용하면서도 자세히 모르는 것 같아서 현타가 와버렸다.ㅠㅠ
기억의 파편들에 리서치로 뼈와 살을 붙여 제대로 HBase를 이해해보자

Write Ahead Log (WAL)

리전 서버는 디스크에 파일이 너무 많이 생성되지 않도록 메모리(memstore)에 충분히 보유한다. 메모리에 데이터를 가지므로 서버에 이슈가 생길 경우 소실 가능성이 있다. 이러한 문제를 해결하기 위해 WAL을 사용한다.

HBase는 모든 변경 사항들을 로그에 쓰고, 연산이 성공했을 때만 클라이언트에 성공했음을 반환한다. 서버가 중지되면 WAL을 사용하여 서버가 중지되기 전까지의 상태 변경 사항을 재현할 수 있다.

StoreFile (HFile)

실제 저장 파일을 구현하는 클래스로, HBase의 데이터를 효율적으로 저장한다는 단 하나의 명확한 목표를 달성하기 위한 클래스
https://github.com/apache/hbase/blob/6cdc4b1f0574cc424480ec2f2e3129f280fa8472/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFile.java

 

출서 - https://blog.cloudera.com/apache-hbase-i-o-hfile/

위 그림은 HFile의 구조인데 File Info, Trailer 외에는 모두 옵셔널한 블록이다. 하지만 Data 블록는 실질적으로 저장되는 데이터를 담기 때문에 거의 대부분 하나의 데이터 블록은 존재할 것이다.
Data 블록은 key (로우 키 길이, 로우키, 컬럼 패밀리 길이, ...), value 로 이루어져 있다. 키에는 많은 정보가 담겨져 있으므로 불필요하기 긴 이름의 키 설정을 지양해야 한다.

변경 사항 복구

리전이 열리면 'recovered.edits' 디렉터리가 있는지 확인한다. 디렉토리가 존재하면 HBase 변경사항이 저장된 내부의 파일들을 읽어 memstore에 저장한다. 파일들은 일련번호가 포함된 이름순으로 정렬되어 있으므로 순서대로 복구할 수 있다. 이 때 일련번호가 디스크에 저장된 저장 파일(HFile)의 일련번호와 같거나 작으면 이미 모든 내용이 반영된것으로 판단하고 무시한다.
모든 edit 파일을 체크하면 memstore의 내용들은 디스크(HFile)로 저장하도록 강제 flush를 하고, edit 파일들은 삭제한다.

Zookeeper와 HBase (WIP)

http://hbase.apache.org/book.html#trouble.namenode.hbase.objects

반응형

의미있는 이름

목차


의도를 분명히 밝혀라

이름을 지을 때 아래의 질문들을 고려해야 한다.

  • 변수(혹은 함수나 클래스)의 존재 이유는?
  • 수행 기능은?
  • 사용 방법은?

Bad

public List<int[]> getThem() {
  List<int[]> list1 = new ArrayList<int[]>();
  for (int[] x : theList)
    if (x[0] == 4)
        list1.add(x);
  return list1;
}

복잡한 코드는 아니지만 해당 메서드가 무엇을(them) 가져오는 것인지, List에 담기는 int[] 배열은 무슨 데이터인지, 4는 무슨 의미를 가지는지를 알 수 없다. 이 말은 곧 각 변수들의 정보를 모르는 경우 코드의 맥락을 완전히 이해 할 수 없다는 뜻이다.
각 변수들의 정보를 모르더라도 이해할 수 있도록 아래와 같이 수정할 수 있다.

Good

public List<Cell> getFlaggedCells() {
  List<Cell> flaggedCells = new ArrayList<Cell>();
  for (Cell cell : gameBoard)
    if (cell.isFlagged())
      flaggedCells.add(cell);
  return flaggedCells;
}

 

그릇된 정보를 피하라

  • 약어를 지양하자
  • 여러 계정을 그룹으로 묶을 때 List와 같은 특정 컨테이너의 사용을 지양하라 (e.g., accountList -> Accounts)
  • 네이밍은 서로 비슷한 이름을 사용하지 말자
  • 유사한 개념은 유사한 표기법을 사용하자, 일관성이 떨어지는 표기법은 그릇된 정보이다.
  • 다른 글자와 혼동되는 단일 알파벳을 피하자 (e.g., 소문자 L <-> 1, 대문자 I)

 

의미 있게 구분하라

한 scope에서 동일 이름을 사용할 수 없으니 컴파일러를 통과하기 위한 무의미한 철자 변경의 오류를 범하지 않도록 해야 한다. 무의미한 철자 변경의 대표적인 두가지 예시는 아래와 같다.

  • 연속된 숫자를 덧붙이기
    Bad :

    public static void copyChars(char a1[], char a2[])

    Good :

    public static void copyChars(char souce[], char destination[])
  • 불용어(noise word) 추가
    불용어란? 없어도 의미 전달에 영향이 없는 단어

    • 접두어 사용을 조심하자
      a, an, the와 같은 접두어는 의미가 분명히 다를 때만 사용하도록 한다. (e.g., 모든 지역변수는 a 접두사 사용, 모든 함수 인수는 the 접두사 사용)
    • 불용어를 사용하여 중복을 발생시키지 말자
      product라는 클래스가 존재 할 때 ProductInfo, ProductData와 같은 개념이 구분되지 않는 클래스를 생성하여 중복을 발생시키지 않도록 한다. (e.g., Money & MoneyAccaount, CustomerInfo & Customer, AccountData & Account)

 

발음하기 쉬운 이름을 사용하라

발음하기 어려운 단어는 커뮤니케이션에도 영향을 끼친다. 이는 실제 존재하는 단어를 사용하는 것만으로도 해결이 된다.

Bad :

아 래의 변수는 generate date, year, month, day, hour, minute, second 의 줄임말이다.

Date genymdhms

Good :

Date generationTimetamp

 

검색하기 쉬운 이름을 사용하라

  • 상수
    상수값에 버그가 있을 경우 검색으로 찾아낼 수 없다. 그러나 상수값의 의미를 나타내는 변수로 정의하여 사용하면 검색에 용의하다.

  • 변수
    알파벳 하나를 변수로 사용하면 검색이 어렵다.

Bad :

int s = 0;
for (int i = 0; i < 30; i++) 
  s += i * 4;

Good :

int maxIndex = 30;
const int MULTIPLICATION_CONDITION = 4;
int sum = 0;
for (int i = 0; i < maxIndex; i++) // 하나의 메서드에서만 쓰이며, 다시 쓰이지 않는다면 한 문자 변수도 나쁘지 않다
  sum += i * MULTIPLICATION_CONDITION;

 

인코딩을 피하라

  • 헝가리식 표기법을 지양하라
    과거 프로그래밍 언어는 변수 및 함수의 인자 이름 앞에 데이터 타입을 명시하는 헝가리식 표기법을 사용하였으나 현대의 프로그래밍 언어는 많은 컴파일러가 타입을 기억하고 강제하므로 네이밍 시 타입을 직접 명시하는 것을 피하는 것이 좋다. 오히려 아래와 같은 문제가 발생 할 수 있다.

    PhoneNumber phoneString; // 이러한 경우 타입이 바뀌게 되었을 때 변수명도 바꿔주어야 하는 문제가 생긴다.
  • 멤버 변수 접두어
    멤버 변수임을 명시하기 위해 "m_" 접두어를 붙이는 것을 지양하고 클래승와 함수는 접두어가 필요없을 정도로 작게 구현해야 한다.

  • 인코딩이 필요한 경우?
    Abstract Factory를 구현하는 경우, 인터페이스 클래스 이름보다는 구현 클래스의 이름을 인코딩 하는 것이 좋다.
    Bad :

    public interface IShapeFactory;  // 인터페이스 클래스
    public class ShapeFactory;  // 구현 클래스

    Good :

    public interface ShapeFactory;  // 인터페이스 클래스
    public class ShapeFactoryImp;  // 구현 클래스
    public class CShapeFactory;  // 구현 클래스

 

자신의 기억력을 자랑하지 마라

  • 하나의 문자만 사용하는 것을 지양하라
    • 루프에서 반복 횟수 변수는 전통적으로 한 글자만을 사용
      보통 i, j, k를 사용 (소문자 l은 대문자 I와 헷갈리므로 절대 안됨!)
    • 이외에는 대부분 적절하지 않다
  • 나만 이해할 수 있는 변수명이 아닌 모두가 이해할 수 있는 명료한 네이밍을 지향하자

 

클래스 이름

  • 동사가 들어가지 않는 명사/명사구가 적합하다.
  • 불용어를 지양하자 (e.g., Manager, Processor, Data, Info)

Good :

public class Customer
public class WikiPage
public class AddressParser

 

메서드 이름

  • 동사/동사구가 적합하다.

  • 접근자(Accessor), 변경자(Mutator), 조건자(Predicate)는 javabean 표준에 따라 get, set, is를 붙인다.
    e.g.,

    String name = employee.getName();
    customer.setName("mike");
    if (paycheck.isPosted());
  • 생성자의 중복정의 시 정적 팩토리 메서드를 사용한다. (이때, 생성자 사용을 제한하려면 해당 생성자를 private으로 사용한다.)

    • 해당 내용의 상세한 특징은 Effective Java 3/E 기준 Item1을 참고한다.

    Bad : 

    Complex fulcrumPoint = new Complex(23.0);

    Good : 

    Complex fulcrumPoint = Complex.FromRealNumber(23.0);

 

기발한 이름은 피하라

  • 특정 문화, 배경지식이 있어야 이해할 수 있는 이름이 아닌 명료한 이름을 선택하여 의도를 분명하고 솔직하게 표현하라

 

한 개념에 한 단어를 사용하라

  • 똑같은 기능을 하는 메서드는 모든 클래스에서 하나의 이름으로 통일한다.
    (e.g., 각 클래스마다 fetch, retrieve, get으로 다르게 구현하지 않도록 한다.)
  • 주석이 필요하지 않도록 메서드 이름은 독자적이고, 일관적이어야 한다.
  • 동일 layer의 클래스는 하나의 이름으로 통일한다.
    (e.g., 하나의 프로젝트에서 DeviceManager, ProtocolController와 같이 같은 의미지만 다른 단어의 혼용을 피한다.)

 

말장난을 하지마라

  • 한 개념에 한 단어를 사용하라 규칙을 따르되, 일관성을 고려한다.
  • 같은 맥락일때만 같은 이름을 사용하여 코드 내용을 확인하지 않아도 기능이 보장되도록 해야 한다.

 

해법 영역에서 가져온 이름을 사용하라

  • 모든 이름에 도메인 영역의 단어를 사용하지 않는다. 기술 개념에는 기술 이름이 가장 적합한 선택이다. (e.g., JobQueue, AccountVisitor)

 

문제 영역에서 가져온 이름을 사용하라

  • 적절한 기술 이름이 없는 경우 또는 도메인 영역과 관련이 깊은 코드에 도메인 영역의 이름을 사용한다.
  • 우수한 프로그래머라면, 해법(기술) 영역과 문제(도메인) 영역을 구분할 줄 알고 각 영역에 알맞은 네이밍을 정해야 한다.

 

의미 있는 맥락을 추가하라

  • 네이밍은 독자적으로 문맥을 가지기 보단 클래스, 메서드, name space의 위치에 따라 맥락을 부여한다.
  • 접두어는 최후의 수단으로 붙인다.
  • 특정 문맥을 가지는 클래스를 생성하면 컴파일러에게도 문맥이 분명해진다.

Bad : 

  • 메서드의 멤버 변수로 사용될 때 어디에 어떻게 이용될지는 길고 복잡한 메서드를 다 읽어야만 이해할 수 있다.
  • 조건문으로 분기되어 변수의 값을 세팅해주지만 해당 값의 의미는 알 수 없다.
private void printGuessStatistics(char candidate, int count) {
  String number;
  String verb;
  String pluralModifier;
  if (count == 0) {
    number = "no";
    verb = "are";
    pluralModifier = "s";
  }
  else if (count == 1) {
    number = "1";
    verb = "is";
    pluralModifier = "";
  } else {
    number = Integer.toString(count);
    verb = "are";
    pluralModifier = "s";
  }
  String guessMessage = String.format("There %s %s %s%s", verb, number, candidate, pluralModifier);
  print(guessMessage);
}

Good : 

  • 클래스의 멤버 변수가 됨으로써 통계 추측 메세지에 사용되는 값임을 클래스의 이름만으로 알 수 있다.
  • 메서드로 분리함으로서 값을 세팅할 때 어떠한 의미를 가지는 값을 세팅하는지 명확해진다.
public class GuessStatisticsMessage {
  private String number;
  private String verb;
  private String pluralModifier;

  public String maek(char candidate, int count) {
    createPluralDependentMessageParts(count);
    return String.format(
      "There %s %s %s%s",
      verb, number, candidate, pluralModifier);
  }

  private void createPluralDependentMessageParts(int count) {
    if (count == 0) {
      thereAreNoLetters();
    } else if (count == 1) {
      thereIsOneLetter();
    } else {
      thereAreManyLetters(count);
    }
  }

  private void thereAreManyLetters() {
    number = Integer.toString(count);
    verb = "are";
    pluralModifier = "s";
  }

  private void thereIsOneLetter() {
    number = "1";
    verb = "is";
    pluralModifier = "";
  }

  private void thereAreNoLetters() {
    number = "no";
    verb = "are";
    pluralModifier = "s";
  }
}

 

불필요한 맥락을 없애라

  • 모든 클래스를 아우르는 맥락을 굳이 접두어로 사용하지 않는다.

    • IDE에서 해당 접두어를 입력하는 순간 수많은 클래스가 열거되어 정말 필요한 클래스를 찾기 어려워진다.
    • 굳이 접두어를 붙임으로서 이름이 불필요하게 너무 길어진다. 긴 이름이 짧은 이름보다 좋지만 의미가 분명한 경우에 한해서이다.

    Bad : 

    package com.gsd;
    
    public class GsdAccountAddress

    Good : 

    package com.gsd;
    
    public class AccountAddress
  • 클래스의 이름으로 좋은 것과 인스턴스의 이름으로 좋은 것은 다르다.

 

마치면서

좋은 이름을 선택한다는 것은 결국 가독성을 높이기 위한 것


참고하면 좋을 문서

반응형

'Dev > Books' 카테고리의 다른 글

[CleanCode] 7장. 예외 처리  (0) 2020.05.16
[CleanCode] 6장. 객체와 자료 구조  (0) 2020.05.15
[CleanCode] 5장. 형식 맞추기  (0) 2020.05.12
[CleanCode] 4장. 주석  (0) 2020.05.12
[CleanCode] 3장. 함수  (0) 2020.05.06

+ Recent posts