VisualWorksTutorial1:Page12

From 흡혈양파의 번역工房
Jump to navigation Jump to search

cincom_tutorial_vwlogo
cincom_tutorial_cincomlogo

웹로그 통계 레슨 11
리팩토링(Refactoring)

cincom_tutorial_stlogo

| 목차 | 레슨10| 정리 |
cincom_tutorial_openbook 리팩토링은 Smalltalk 세계에서 이따금 들을 수 있는 전문용어입니다. 간단히 설명하자면, 코드의 재사용이나 생산성 향상을 목적으로 다시 쓴 코드를 의미합니다. 광범위한 의미로는, 가능한한 개량된 코드를 "정리"해서 처리를 단순히 하는 것이라고도 말할 수 있습니다
cincom_tutorial_certificate 이 튜토리얼의 마지막 레슨입니다. 코드를 리팩토링해서 불필요한 코드를 정리합니다. 이 레슨은 각 코드행을 설명해온 지금까지의 레슨과는 다릅니다. 이 레슨에서는 기존 메서드에 어떠한 개선이 이루어졌는가, 그리고 어째서 새로운 메서드를 작성할 필요가 있었는지를 확인합니다. 1행 1행 설명하지는 않습니다만, 전체적인 설명은 하겠습니다
cincom_tutorial_design 이번에 하게되는 리팩토링에서는 아래와 같은 기능강화나 수정이 진행됩니다.
  1. getLogFiles 메서드는 로그파일의 일람을 돌려줍니다.
  2. 웹Hit 표시는 Transcript에서 행하여지고 있습니다. 페이지 카운트는 파일에 기록되고 있습니다. 웹Hit도 파일로 기록하겠습니다.
  3. 어플리케이션이 재실행되기 전에 모든 "통계"파일을 삭제하는 제한은 제거합니다. ".log"의 필터에서 파일을 취득하지 않도록 출력 파일의 이름을 변경합니다.
  4. 두 개의 통계를 생성하는 "개시" 메서드는 공통화합니다.
cincom_tutorial_steps 1. VisualWorks 메인 런쳐 화면에서 툴바의 네 번째 버튼을 클릭하거나, 브라우저>>시스템 메뉴를 선택해주십시오.


2. 패키지 창(맨 왼쪽)에서 XML패키지까지 일람을 스크롤해주십시오. 그리고 WebLogStats 패키지를 반전(선택)해주십시오.


만일 WebLogStats 패키지를 찾지 못한 경우에는 파일인할 필요가 있습니다. 이 레슨에서는 앞서 레슨에서 행했던 작업을 VisualWorks 개발환경에 로드할 필요가 있습니다.


3. getLogFiles 메서드를 다음과 같이 바꿔주십시오.

getLogFiles 

| workingDir contents xFound logFiles | 
logFiles := Set new. 
workingDir := logDirectory asFilename. 
contents := workingDir directoryContents. 
contents do: [ :each | 
xFound := each findString: filter startingAt: 1. 
xFound = 1 
ifTrue: [ logFiles add: each. ] ]. 
^logFiles.


4. <오퍼레이트 클릭>후 억셉트를 선택해주십시오.


변경 이유는 매우 간단합니다. 오리지날 getLogFilesgetLogFilesForPageCounts 메서드를 비교하면, 기본적으로는 같은 일을 합니다. 차이점은, Hit 계산에서 사용되는가, 페이지 카운트의 통계에서 사용되는가입니다. 이것은 여분의 코드이며, 좋은 것이 아닙니다. 메서드를 실행하는 지시가 실제로는 하나의 메서드가 아닌 것은 왜 일까요-getLogFile? 위의 코드가 그것을 하고 있습니다. 필터에 의해 디렉토리에 있는 파일을 모아 Set 객체에 격납합니다. 이로서 재사용 가능한 메서드가 되었습니다. 메서드가 다른 메서드를 잘 이해할 필요는 없습니다.


재사용 가능 개념에 대해 요약할 필요는 없겠지요. 얼마나 많은 사람이 이 사이트에 방문했는지, 로그파일을 검색하는 다른 루틴이 필요하다는 가정을 합니다. 그 경우, getLogFiles 메서드나 getLogFilesForPageCounts 메서드의 클론을 작성했던 것 처럼, showHitshowPageCounts 어느쪽인가를 참조하고있는 행을 변경하여, getDutationTimes와 같은 무언가로 치환합니다. 여기서 문제가 발생합니다. 웹마스터가 로그파일을 복수의 디렉토리에 보존하기로 결정했다고 가정(의논 목적으로)합니다. 그리고, 이로인해 세 개의 메서드 변경을 강요받습니다. 위에서 논한 작업을 하기 위한 메서드 코딩을 하나의 메서드를 변경하는 것으로 끝내려 합니다.


마지막 주의 : 필터에 일치하지만 로그파일이 아닌 파일을 읽어들이는 문제를 피하기 위해서 xFound의 조건을 "0보다 큰"에서 0과 동일한으로 변경합니다. 조건은 1의 위치에서 ws00문자열을 검색하는 상태입니다. 다른 메서드에서 페이지 카운트가 포함되어있는 파일명의 일부로서 자신의 이름(ws00문자열을 포함)을 파일에 사용하고 있습니다. "0보다 큰"은 필요 없는 참이 되돌아옵니다.


5. 새로운 메서드를 작성합니다. 다음과 같이 메서드 코드 패널의 텍스트를 치환해주십시오.

getRootName: aFile 
| line | 
line := aFile copyUpTo: $.. 
^line.


6. <오퍼레이트 클릭>Accept를 선택해주십시오.

로그파일 이름(ws000101.log)은 이 메서드에 건내어집니다. 파일이름은 String 객체이기 때문에 문자열 조작이 가능합니다. 여기서는 파일 이름에서 확장자 ".log"를 삭제한 파일명이 필요하기 때문에, .까지의 문자열을 돌려줍니다. 이 작업에 의해 파일 이름에서 ".log"를 삭제하여, 의미있는 출력파일 이름에 문자를 추가하기 쉬워집니다.


7. showPageCount: 메서드를 선택하고 다음과 같이 바꿔주십시오.

showPageCounts: aFile 

| stream line bag xFound sort | 
bag := Bag new. 
stream := (logDirectory, '\', aFile) asFilename readStream. 
[ stream atEnd ] whileFalse: [ 
line := stream upTo: Character cr. 
line := line copyFrom: 50 to: line size. 
line := line copyFrom: (line indexOf: $/) to: line size. 
line := line copyUpTo: $,. 
xFound := (line findString: '.asp' startingAt: 1). 
xFound > 0 
ifTrue:[ bag add: line. ]. ]. 
stream close. 
sort := SortedCollection sortBlock: [:a :b| a >= b]. 
bag valuesAndCountsDo: [ :each :count | 
sort add: (Association key: count value: each)]. 
^sort


8. <오퍼레이트 클릭>Accept를 선택해주십시오.

출력 파일을 생성하는 코드를 삭제하고, 정렬된 컬렉션을 돌려주는 행에 치환합니다. 그 외의 메서드에서 외부파일에 컬렉션을 써냅니다.


9. 다른 신규 메서드를 작성합니다. 다음과 같이 바꿔주십시오.

startHits 

| logFiles myHits count out outFile| 
myHits := SortedCollection new. 
logFiles := self getLogFiles. 
logFiles do: [ :each | 
outFile := '웹sitehits.txt'. 
count := self showHits: each. 
myHits add: (Association key: count value: each). ]. 
out := (logDirectory, '\' , outFile) asFilename writeStream. 
myHits do: [ :each | out cr; nextPutAll: (each printString).]. 
out close. 
Dialog warn: 'Site hits complete'.


10. <오퍼레이트 클릭>Accept를 선택해주십시오.


Association을 포함한 myHits라 불리우는 새로운 컬렉션을 생성합니다. 로그파일과 로그파일에서 얻은(count) Hit수를 연결합니다. 모든 로그파일이 처리되면, 컬렉션을 외부 파일로 출력하기 위한 준비가 됩니다.


11. startPageCount 메서드를 선택해주십시오. 이 메서드로의 변경은 매우 광범위하기 때문에 아래와 같은 메서드로 만드는 것이 가장 좋습니다.

startPageCount 

| logFiles count rootName out | 
logFiles := self getLogFiles. 
logFiles do: 
[ :each | 
rootName := 'pagecounts_', (self getRootName: each) , '.txt'. 
count := self showPageCounts: each. 
out := (logDirectory, '\' , rootName) asFilename writeStream. 
1 to: 10 do: [ :xx | out cr; nextPutAll: (count at: xx) printString.]. 
out close. 
]. 
Dialog warn: 'Page Counts Complete'.


12. <오퍼레이트 클릭>Accept를 선택해주십시오.


모든 로그파일에 대해, ".log"에서 취득해서 ".txt"와 그 접두어로서 "pagecount_"로 치환합니다. "필터"문자를 가지지 않는, 중복되지 않는 파일명을 생성합니다. 그리고 페이지 카운트를 취득하는 메서드를 부르고, 정렬된 컬렉션이 돌아와 count에 격납됩니다. 이어서 외부 파일에 컬렉션 맨 처음 10가지 요소를 써냅니다.


13. 다음과 같이 start 메서드를 수정해주십시오.

start 

filter := (Dialog request: '필터를 입력해주십시오' 
initialAnswer: 'ws00').
(filter size) > 0
ifTrue: [ self startHits.
self startPageCount.
Dialog warn: '모든 통계를 실행하였습니다'. ]
ifFalse: [ Dialog warn: '이상없음, 안녕히계십시오'].


14. <오퍼레이트 클릭>Accept를 선택해주십시오

이 메서드는 필터를 요구합니다. 입력하면 통계를 수집하는 두 개의 메서드를 호출합니다. 지금까지 두 개의 메서드에서 사용된 필터의 요구였습니다만, 지금은 하나로 만들었습니다. 이것은 매우 좋은 작업입니다. 예를 들어, 웹마스터가 로그파일의 확장자를 "log"에서 ".wlg"로 변경하고 싶다고 가정합시다. 예전 같았으면, 두 개의 메서드 프롬프트 표시에 대해 변경하지 않으면 안되었습니다.

필터를 입력하면 Cancel을 실행할 수 없습니다. 양쪽 다 통계 메서드를 호출합니다. 이 코드들 가운데 새로운 내용은 한 가지밖에 없습니다. 전형적인 "If-Then-Else"구문의 예시입니다.


15. VisualWorks 표준 디렉토리의 모든 ".stat"필터가 삭제된 것을 확인해주십시오. ".stat"필터가 남아있으면 에러가 발생합니다. startPageCount메서드 안의 이 문제를 해결했기에, 삭제하는 작업은 맨 마지막이 될것입니다.

WebLogClass new start


모든 텍스트를 반전시키고 <오퍼레이트 클릭>실행을 선택해주십시오.


이 코드는 웹Hit와 페이지 카운트 통계파일을 생성합니다. 그리고 다이얼로그 박스가 진행상태를 보고합니다.


16. 파일 브라우저 다이얼로그 박스를 열고 로그파일이 있는 장소로 이동해주십시오. 내용을 확인할 수 있습니다.


17. 지금까지의 작업을 보존합니다. 보존 방법을 잊어버렸다면 레슨 8을 참조해주십시오.

cincom_tutorial_certificate 정리

리팩토링은 재사용 가능하도록 코드를 개선합니다. 눈에 띄는 성과중 하나로서, getLogFile메서드에 대한 수정이 있었습니다. 많은 작업에 대해 작은 변경을 하는 것으로 인해, 두 가지 메서드를 재사용 가능하게 만들었습니다. 예전과 같은 상태였다면, 사이트에 몇 명이 방문했는지 조사하는 코드를 적고, 모든 로그파일 가운데서 정보를 뽑아낼 필요가 있었습니다. 리팩토링 작업 덕분에, 이 작업에 있어서 getLogFiles를 사용(재사용)할 수 있었습니다.


리팩토링 작업이 끝은 아닙니다. 누군가 당신의 코드를 보고, 그 메서드보다 더욱 효율적인 코드를 적을지도 모릅니다. 예를 들어 아래의 getRootName: 메서드를 생각해 봅시다.

getRootName: aFile 

| line | 
line := aFile copyUpTo: $.. 
^line.

이 코드는 아래와 같이 수정할 수 있습니다

getRootName: aFile 

^aFile copyUpTo: $..

이것은 눈에 띌만한 수정(템퍼러리 변수의 선언은 필요 없었습니다. 그 덕분에 앞의 메서드보다 이 메서드가 적은 메모리로 작업할 수 있습니다)입니다. 가능하다면 수정해주십시오. 재차 말씀드립니다만, 메서드를 간결하게 적는 것은 Smalltalk의 특징이자 "문화"입니다.

이것으로 웹서버 로그해석 연습을 끝내겠습니다. 수고하셨습니다.


아래와 같은 내용을 학습하였습니다

  • 보다 효율적으로 재사용 가능한 코드를 적는 법
  • 전형적인 “If-Then-Else”구문의 코드
  • 특정 메서드에서 다은 메서드로 데이터를 건내는 방법

| 목차 | 레슨10 | 정리 |