2020년 7월 29일 수요일

포카 요케 (poka-yoke)

품질 관리의 측면에서 실수를 방지하도록 행동을 제한하거나 정확한 동작을 수행하게끔 하도록 강제하는 여러 가지 제한점을 만들어 실패를 방지하는 방법을 말하는 용어. 토요타의 시게오 신고에 의해 처음으로 고안됐으며, 실수를 피하다라는 뜻의 일본어에서 왔다.
... 인지 심리학 및 인간의 컴퓨터 상호작용 분야에서도 이를 이용하면 여러 가지 실수를 방지하는 디자인 원리의 하나로 받아들여져서 이용하고 있다.
[위키피디어]

생활에서의 포카 요케 예
- 자동차 기어가 "P"에 있지 않으면 시동이 걸리지 않도록 함.
- USB 장치를 꼽을 때 뒤집어서 꼽으면 작동하지 않음.
- 문이 닫히기 전에 전자 레인지가 작동하지 않음.

이 개념을 제안한 사람은 토요타 생산 시스템의 개척자 중 한 명인 시게오 신고로 '제로 결함'이라는 아이디어를 제안한 품질 전문가였다고 한다.

실수가 발생하지 않도록 끊임없이 노력한다는 철학이 포함된다. 최종 제품의 품질이 올라가려면 연결된 모든 프로세스에서 일정 수준 이상의 품질이 제공되어야 한다. 따라서 결함이 후속 프로세스로 이어지는 것을 방지해야 한다. (완제품 상태에서 결함이 발견되는 것이 가장 나쁜 케이스)

실수 방지 목표를 달성하는데 도움이 되는 특징은 다음과 같다.
- 단순함 : 솔루션이 복잡하지 않고 오류 발생 문제를 명확히 해결해줄 수 있어야 한다.
- 자동화 : 사람의 추가 개입이 없으면 좋다.
- 즉각적인 피드백 : 조건이 사양을 벗어난 경우 즉시 피드백을 해주면 좋다.

-
아예 실수를 할 수 없게끔 하면 사용자가 제품이나 프로세스에 대해 생각할 필요가 없을 것이다.
또는 프로세스를 벗어나는 경우 피드백을 줘서 프로세스 안에서만 행동이 있게끔 유도할 수 있다. 
(정해진 순서 또는 경우의 수 내에서만 행동을 제한하는 것.)

2020년 7월 21일 화요일

입출력 다중화 (파일 디스크립터, select)

입출력 다중화는 단일 프로세스에서 여러 개의 파일을 제어할 수 있도록 해준다. 입출력 다중화는 여러 개의 파일을 다루기 위해서, 파일 기술자(FD, File Descriptor)를 배열(그룹)로 관리한다. 데이터 변경을 감시할 파일 기술자를 배열에 포함시키고, 배열에 포함된 파일 기술자에 변경이 발생하면 파일 기술자에 대응하는 배열에 표시하는 방식이다. 사용자는 파일 기술자 배열의 값을 검사(FD_ISSET)하는 방식으로 여러 개의 파일을 처리할 수 있게 된다. (일반적으로 파일 기술자 테이블의 크기는 1024라 한다. 이는 프로세스가 열 수 있는 파일의 최대 개수, 파일 기술자 테이블의 크기로부터 영향을 받는다.)

• fd_set 구조체
typedef struct
{
    int fds_bits[32];
} fd_set;

변경의 확인은 이벤트 기반이 아니므로, 배열에 있는 모든 값을 전부 검사해야 하는데 1000개의 클라이언트가 연결되어 있다고 가정할 경우 1000개의 필드를 모두 검사해야 한다. 이 방식은 병렬 처리가 아니기 때문에 주의할 필요가 있는데 서버가 하나의 클라이언트를 처리하는 동안 다른 클라이언트는 대기해야 한다. 따라서 상대적으로 데이터 처리 과정이 짧은 서비스에 적합한 방식이라 볼 수 있다.

변경에 대한 확인은 select() 함수를 통하는데 select 함수는 데이터가 변경된 파일의 개수를 반환한다. 데이터가 변경된 파일의 목록을 반환하는 것이 아니기 때문에 사전에 연결된 파일의 번호를 가지고 있지 않으면 배열의 개수만큼 루프를 돌아야 할 수도 있다. (참고로 파일 디스크립터는 0부터 채번되고, 프로세스에서 사용하지 않는 가장 작은 값을 할당한다. 일반적으로 0번은 stdin, 1번은 stdout, 2번은 stderr.)

• FD_ZERO : fd_set 구조체를 초기화 한다. (모든 비트 값을 0으로 세팅)
fd_set rfds;
FD_ZERO(&rfds); // memset(&rfds, 0, sizeof(fd_set));

• FD_SET : 특정 파일 디스크립터를 fd_set 변수에 추가할 때 사용한다.
int fd_socket = socket(AF_INET, SOCK_STREAM, 0);
fd_set rfds;

FD_ZERO(&rfds);
FD_SET(fd_socket, &rfds);

• FD_ISSET : fd_set 변수의 특정 파일 디스크립터를 가리키는 비트가 1인지 확인한다.

• select() : fd_set 변수에서 1로 세팅된 파일 디스크립터에서 이벤트가 발생하면 이를 감지한다.
fd_set rfds, _fds;

FD_ZERO(&rfds);

FD_SET(1, &rfds);
FD_SET(3, &rfds);

max_fd = 3;

while (1) {
    _fds = rfds; // select() 후 fd_set 변수의 내용이 변경되므로 매번 복사본을 전달.
  
    select(max_fd + 1, &_fds, NULL, NULL, NULL); // 1, 3 값을 갖는(FD_SET으로 설정된) 파일 디스크립터의 이벤트를 감시한다.

    // ...
}

* 위 내용에서 '파일'은 '소켓'을 포함한다. (과거 시스템에서 소켓, 장치를 모두 파일의 개념으로 관리했었던 것에서 유래.)

참고 사이트: https://www.joinc.co.kr/w/Site/system_programing/File/select