삽질의 현장/- ETC

프로그램을 작성하는 33가지 방법 - Chaptor 01 정리

shovelman 2019. 3. 10. 00:44

최근 '프로그래밍 패턴 (프로그램을 작성하는 33가지 방법)' 을 읽기 시작했다.

한 가지의 기능을 Chaptor 마다 각각 다른 패턴으로 구현하여 설명한 책이다.

모두 비슷하게 동작하지만 환경과 상황이라는 제약 조건 안에서 탄생된 패턴을 직접 코드로 보여주고 있어
직접 코딩을 하며 이해하고 있는 중이다.


책에서 소개하는 한 가지 기능은 '텍스트 파일을 읽어 단어 빈도 출력' 하는 프로그램이다.

가장 빈도가 높은 단어 순으로 그에 해당하는 빈도를 내림차순으로 출력하는 기능을 구현하고 있다.

Chaptor 01. 그리운 옛날

Chaptor 01 에서는 메모리 제약으로 메모리 관리를 중요시한 시대에서 작성하는 패턴을 설명하고 있다(대략 1950~60년대).

제한적인 메모리를 가지고 원하는 기능을 구현한 패턴을 간략하게 살펴보자. (전체 코드는 링크를 통해 확인할 수 있다.)

패턴

1. 메모리 한계로 사용 가능한 메모리 전체에 걸쳐 데이터를 회전시키고 계산 작업을 복잡하게 했다.

# 입력 파일을 연다
f = open(sys.argv[1])

# 입력 파일 내의 각 줄을 순회
while True:
	data[1] = [f.readline()]  
    if data[1] == ['']: # 입력 파일 끝
        break
    if data[1][0][len(data[1][0])-1] != '\\n': #\\n으로 끝나지 않으면
        data[1][0] = data[1][0] + '\\n' # \\n을 추가한다
	 ... (생략) ...

# 입력 파일 처리를 마쳤다
f.close()

주기억 장치에서 사용할 파일을 읽고 파일의 라인 수 만큼 순회하며 데이터를 처리하는 코드이다.



2. 식별자가 없어 주석과 문서화를 통해 식별자를 설명했다.

data.append([]) # data[1]은 (최대 80자인) 줄
data.append(None) # data[2]는 단어의 시작 문자 색인
data.append(0) # data[3]은 문자에 대한 색인이며 i=0
data.append(False) # data[4]는 단어를 찾았는지 여부를 나타내는 플래그
data.append('') # data[5]는 해당 단어
data.append('') # data[6]은 단어, NNNN
data.append(0) #data[7]은 빈도

index마다 어떤 역할을 하는지 주석으로 설명은 되어있지만,
익숙치 않은 사람이 해당 코드 분석하기에 매우 불편한 것은 사실이다.

이 당시 협업을 하기 힘들었던 이유를 이러한 코드만 봐도 이해할 수 있을 것 같다.



3. 주기억 장치에 맞지 않은 데이터를 저장하기 위해 '보조 기억 장치(파일)'를 과도하게 사용했다.

f = open('../stop_words.txt')
# 보조 기억 장치를 연다
word_freqs = touchopen('word_freqs', 'rb+')

... (생략) ...

while True:
      data[6] = word_freqs.readline().strip()
      if data[6] == '':
          break;
      data[7] = int(data[6].split(',')[1])
      # 공백 문자가 없는 단어
      data[6] = data[6].split[','][0].strip()
      if data[5] == data[6]:
          data[7] += 1
          data[4] = True
          break
 if not data[4]:
      word_freqs.seek(0, 1) # 윈도우에서는 필요하다
      word_freqs.writelines("%20s,%04d\\n" % (data[5], 1))
 else:
      word_freqs.seek(-26, 1)
      word_freqs.writelines("%20s,%04d\\n" % (data[5], data[7]))
 word_freqs.seek(0,0)

... (생략) ...

# 입력 파일 처리를 마쳤다
f.close()
word_freqs.flush()

주기억 장치는 메모리 제약이 있기 때문에 프로그램의 성능을 위한 전략으로 보조 기억 장치를 활용하였다.



4. 메모리에 존재하는 데이터가 얼마나 되는지 신경 써야 했다.

for i in range(25):
    if data[i] == [] or data[i][1] < data[26]:
        data.insert(i, [data[25], data[26]])
        del data[26] # 마지막 요소를 삭제한다
        break


맺으며

수행하는데 무려 2m 20s 나 걸렸다 ...