팀의 다른 프로그래머가 내 코드를 더 읽기 쉽게 만들어야합니다.


11

델파이 에서 프로젝트를 진행 중이며 응용 프로그램 설치 프로그램을 작성 중입니다. 세 가지 주요 부분이 있습니다.

  1. PostgreSQL 설치 / 제거
  2. myapplication ( myapplication 설정은 nsi를 사용하여 작성 됨) 설치 / 제거
  3. 스크립트 (배치 파일)를 통해 Postgres에 테이블 생성

모든 일이 잘 실행하고 원활하게,하지만 뭔가가 실패 할 경우 I, 프로세스의 모든 단계를 LogToFile하는 LogToFileger을 만든
다음과 같이

LogToFileToFile.LogToFile('[DatabaseInstallation]  :  [ACTION]:Postgres installation started');

이 기능 LogToFileToFile.LogToFile()은 파일에 내용을 씁니다. 이것은 잘 작동하지만 문제는 하나의 ca 가 코드의 모든 곳에서 함수 호출 만 볼 때 코드 를 읽기 가 어려워 코드를 엉망으로 만들었다는 것입니다LogToFileToFile.LogToFile()

 if Not FileExists(SystemDrive+'\FileName.txt') then
 begin
    if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then
       LogToFileToFile.LogToFile('[DatabaseInstallation] :  copying FileName.txt to '+SystemDrive+'\ done')
       else
       LogToFileToFile.LogToFile('[DatabaseInstallation] :  copying FileName.txt to '+SystemDrive+'\ Failed');
 end;
 if Not FileExists(SystemDrive+'\SecondFileName.txt')      then
   begin
     if CopyFile(PChar(FilePathBase+'SecondFileName.txt'), PChar('c:\SecondFileName.txt'), False) then
       LogToFileToFile.LogToFile('[DatabaseInstallation] : copying SecondFileName.txt to '+SystemDrive+'\ done')
   else
       LogToFileToFile.LogToFile('[DatabaseInstallation] :  copying SecondFileName.txt to '+SystemDrive+'\ Failed');
 end;

보시다시피 LogToFileToFile.LogToFile()전화 가 많기
전에 전화 가 많이 있습니다

 if Not FileExists(SystemDrive+'\FileName.txt') then
    CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) 
 if Not FileExists(SystemDrive+'\SecondFileName.txt')      then
   CopyFile(PChar(FilePathBase+'SecondFileName.txt'), PChar('c:\SecondFileName.txt'), False)

이것은 지금 내 전체 코드의 경우입니다.
읽기 어렵다.

누구든지 LogToFile에 대한 호출을 방해하지 않는 좋은 방법을 제안 할 수 있습니까?

처럼


  1. 이처럼 'LogToFileToFile.LogToFile ()`호출을 들여 쓰기

       if Not FileExists(SystemDrive+'\FileName.txt') then
         begin
             if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then
            {Far away--->>}                   LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ sucessful')
       else
            {Far away--->>}                   LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ Failed');
       end;
    
  2. 별도의 장치 와 같은 LogToFileger
    이 장치는 모든 LogToFile 메시지 것 switch case같은를

     Function LogToFilegingMyMessage(LogToFilegMessage : integer)
    
     begin
    case  LogToFilegMessage of
    
    1         :  LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ sucessful');
    2         :  LogToFileToFile.LogToFile(2,'[DatabaseInstallation] :  [ACTION]:copying FileName.txt to '+SystemDrive+'\ Failed');
       150        :  LogToFileToFile.LogToFile(2,'[somthing] :  [ACTION]: somthing important);
    
    end;
    

필요할 때마다 LogToFilegingMyMessage (1)을 호출 할 수 있습니다.

누구 든지이 방법으로 LogToFileging에 대한 더 좋고 깔끔한 접근 방식을 말해 줄 수 있습니까?


5
당신의 주제에 대답하기 위해 : 당신은 그들이 팀을 이해하는지 또는 모든 것이 이해되는지 물어 보려고 노력 했습니까? 그렇다면, "충분히"읽을 수 있어야합니다.
Spoike

@Spoike : 나는 어디에서나 logBook.log()만난 것처럼 읽기가 조금 어려웠다 .
PresleyDias

1에서 3까지 번호가 매겨진 "두 개의 주요 부분이 있습니다."나는 왜 당신이 가독성에 의문을 가지고 있다고 생각합니다. 일관성을 위해 "편집"할 수있는 사람을 찾을 수 있습니다.
S.Lott

@ S.Lott 내가 실수에 대한 '2'에서 '3'로 ..sory를 편집
PresleyDias

답변:


11

로깅을 추가했을 때 두 가지를 소개했습니다.

  1. 거의 모든 작업에 대해 해당 작업 (또는 오류)을 기록하는 행을 추가했기 때문에 코드가 커졌습니다.
  2. 로그 라인 자체는 부풀어 오른 것처럼 보이고 공간을 많이 차지하기 때문에 가독성을 떨어 뜨립니다.

이들 각각에는 문제가 있으며 자체적으로 비교적 간단한 해결책이 있습니다.

  1. 코드를 더 작은 함수로 나눕니다. 모든 사본을 포함하고 오류 / 성공에 대한 로그 메시지를 포함하는 하나의 거대한 기능을 사용하는 대신, 정확히 하나의 파일을 복사하고 자체 결과를 기록하는 "CopyFile"기능을 도입 할 수 있습니다. 그렇게하면 기본 코드는 CopyFile 호출로 구성되며 읽기 쉽습니다.

  2. 로거를 더 똑똑하게 만들 수 있습니다. 반복되는 정보가 많은 거대한 문자열을 전달하는 대신 열거 값을 전달하여 더 명확하게 만들 수 있습니다. 또는 LogFileCopy, LogDbInsert와 같이보다 전문화 된 Log () 함수를 정의 할 수 있습니다.

(1)을 따르면 다음과 같은 코드를 가질 수 있습니다.

CopyFile( sOSDrive, 'Mapannotation.txt' )
CopyFile( sOSDrive, 'Mappoints.txt' )
CopyFile( sOSDrive, 'Mapsomethingelse.txt' )
. . . .

그런 다음 CopyFile ()은 작업을 수행하고 결과를 기록하기 위해 몇 줄의 코드 만 필요하므로 모든 코드는 간결하고 읽기 쉽습니다.

서로 다른 모듈에 함께 있어야하는 정보를 분리 할 때 접근 방식 2를 피하십시오. 로그 코드와 동기화되지 않도록 기본 코드를 요청하고 있습니다. 그러나 LogMyMessage (5)를 보면 결코 알 수 없습니다.

업데이트 (의견에 대한 답변) : 사용중인 정확한 언어에 익숙하지 않으므로이 부분을 조금 조정해야 할 수도 있습니다. 모든 로그 메시지가 구성 요소, 작업, 결과의 세 가지를 식별하는 것 같습니다.

이것이 MainMa가 제안한 것과 거의 같습니다. 실제 문자열을 전달하는 대신 상수를 정의하십시오 (C / C ++ / C #에서는 열거 형 열거 형의 일부 임). 예를 들어 구성 요소의 경우 DbInstall, AppFiles, Registry, Shortcuts 등이있을 수 있습니다. 코드를 더 작게 만들면 쉽게 읽을 수 있습니다.

언어가 변수 매개 변수 전달을 지원하는 경우에도 도움이 될 수 있습니다. 예를 들어 action이 "FileCopy"인 경우 파일 이름과 대상 디렉토리라는 두 개의 추가 사용자 매개 변수를 갖도록 해당 조치를 정의 할 수 있습니다.

따라서 파일 복사 줄은 다음과 같습니다.

Bool isSuccess = CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False)
LogBook.Log( DbInstall, FileCopy, isSuccess, 'Mapannotation.txt', sOSDrive )

* 작업 결과를 별도의 로컬 변수에 저장하고 해당 변수를 Log ()에 전달할 수있는 경우 로그 줄을 두 번 복사 / 붙여 넣을 이유도 없습니다.

여기 테마가 보이죠? 덜 반복적 인 코드-> 더 읽기 쉬운 코드.


+1, you could pass in enumerations values 이것 에 대해 좀 더 말씀해 주 시겠습니까?
PresleyDias 2012

@PresleyDias : 게시물 업데이트
DXM

좋아, 네 덜 repetitive-> 더 읽을 수있는 코드를 가지고
PresleyDias

2
+1 "코드를 더 작은 함수로 나누십시오." 당신은 그것을 충분히 강조 할 수 없습니다. 너무 많은 문제가 사라집니다.
Oliver Weiler

10

"LoggableAction"의 개념을 추상화해야 할 것 같습니다. 귀하의 예에서 모든 호출이 성공 또는 실패를 나타 내기 위해 부울을 반환하는 패턴을보고 있으며 유일한 차이점은 로그 메시지입니다.

델파이를 쓴 지 몇 년이 지났으므로 C #에서 영감을 얻은 의사 코드이지만 비슷한 것을 원한다고 생각했을 것입니다.

void LoggableAction(FunctionToCallPointer, string logMessage)
{
    if(!FunctionToCallPointer)
    {  
        Log(logMessage).
    }
}

그러면 당신의 호출 코드는

if Not FileExists(sOSdrive+'\Mapannotation.txt') then
    LoggableAction(CopyFile(PChar(sTxtpath+'Mapannotation.txt'), "Oops, it went wrong")

함수 포인터에 대한 델파이 구문을 기억할 수 없지만 구현 세부 사항에 관계없이 로그 루틴 주위의 추상화는 원하는 것 같습니다.


아마 이런 식으로 나아갈 것입니다.하지만 OP의 코드가 어떻게 구성되어 있는지에 대해 더 많이 알지 못하면 메소드 포인터의 잠재적 혼란을 추가하지 않고 호출 할 몇 가지 추가 메소드를 정의하는 것보다 낫다는 것을 말하기는 어렵습니다 OP가 그러한 것들에 대해 얼마나 알고 있는지
S.Robins

+1, LoggableAction()이것은 좋으며, 확인 및 쓰기 대신 반환 된 값을 직접 쓸 수 있습니다.
PresleyDias 2012

내가 +100, 좋은 대답 좋겠지 만, 난, 난 내 옆에있는 응용 프로그램에서이 제안을하려고합니다 .. :( 아이디어 주셔서 감사 단 하나의 대답을 받아 들일 수
PresleyDias

3

가능한 방법 중 하나는 상수를 사용하여 코드를 줄이는 것입니다.

if CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False) then
   LogBook.Log(2,'[POSTGRESQL INSTALLATION] :  [ACTION]:copying Mapannotation.txt to '+sOSdrive+'\ sucessful')
   else
   LogBook.Log(2,'[POSTGRESQL INSTALLATION] :  [ACTION]:copying Mapannotation.txt to '+sOSdrive+'\ Failed');

될 것입니다 :

if CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False) then
   Log(2, SqlInstal, Action, CopyMapSuccess, sOSdrive)
   else
   Log(2, SqlInstal, Action, CopyMapFailure, sOSdrive)

화면의 문자 수를 계산할 때 더 나은 로그 코드 / 기타 코드 비율을 갖습니다.

: 지금까지 안 갈거야 것을 제외하고 이것은 당신이 당신의 질문의 포인트 2에서 무엇을 제안 가까운 Log(9257)분명히보다 짧은 Log(2, SqlInstal, Action, CopyMapSuccess, sOSdrive)또한 읽기 매우 어렵지만. 9257은 무엇입니까? 성공입니까? 행동? SQL과 관련이 있습니까? 지난 10 년 동안이 코드베이스에서 작업했다면, 그 숫자를 마음에 들게 될 것입니다 (논리가있는 경우 (예 : 9xxx는 성공 코드, x2xx는 SQL과 관련됨 등)) 코드베이스, 짧은 코드는 악몽이 될 것입니다.

두 가지 접근 방식을 혼합하여 더 나아갈 수 있습니다. 단일 상수를 사용하십시오. 개인적으로는 그렇게하지 않을 것입니다. 상수의 크기가 커질 것입니다.

Log(Type2SuccessSqlInstallCopyMapSuccess, sOSdrive) // Can you read this? Really?

또는 상수는 짧지 만 명시 적이지는 않습니다.

Log(T2SSQ_CopyMapSuccess, sOSdrive) // What's T2? What's SSQ? Or is it S, followed by SQ?
// or
Log(CopyMapSuccess, sOSdrive) // Is it an action? Is it related to SQL?

이것은 또한 두 가지 단점이 있습니다. 다음을 수행해야합니다.

  • 로그 정보를 해당 상수에 연결하는 별도의 목록을 유지하십시오. 단일 상수를 사용하면 빠르게 커집니다.

  • 팀에서 단일 형식을 시행하는 방법을 찾으십시오. 예를 들어, 대신에 T2SSQ누군가가 쓰기로 결정하면 ST2SQL어떻게됩니까?


1, 깨끗한 위해 log전화,하지만 당신은 좀 더 그것을 이해하지 못했다 설명 할 수있다 Log(2, SqlInstal, Action, CopyMapFailure, sOSdrive), 당신은 말 뜻 SqlInstal처럼 내 정의 된 변수가 될 것이다 SqlInstal:=[POSTGRESQL INSTALLATION] ?
PresleyDias 2012

@PresleyDias : SqlInstal어떤 값이든 될 수 있습니다 (예 : value) 3. 그런 다음 Log()에서이 값은 [POSTGRESQL INSTALLATION]다른 로그 메시지 부분과 연결되기 전에 효과적으로 변환됩니다 .
Arseni Mourzenko

single format in your team좋은 / 좋은 옵션입니다
PresleyDias

3

지저분하게 보이는 모든 것을 처리하기 위해 일련의 작은 함수를 추출하십시오. 한 곳에서 쉽게 수행 할 수있는 반복되는 코드가 많이 있습니다. 예를 들면 다음과 같습니다.

procedure CopyIfFileDoesNotExist(filename: string);
var
   success: boolean;
begin
   if Not FileExists(sOSdrive+'\'+filename') then
   begin
      success := CopyFile(PChar(sTxtpath+filename), PChar(sOSdrive+filename), False);

      Log(filename, success);
   end;
end;

procedure Log(filename: string; isSuccess: boolean)
var
   state: string;
begin
   if isSuccess then
   begin
      state := 'success';
   end
   else
   begin
      state := 'failed';
   end;

   LogBook.Log(2,'[POSTGRESQL INSTALLATION] : [ACTION]:copying ' + filename + ' to '+sOSdrive+'\ ' + state);
end;

비결은 코드에서 중복을보고 제거하는 방법을 찾는 것입니다. 많은 공백을 사용하고 시작 / 종료를 유리하게 사용하십시오 (공백이 많고 코드 블록을 쉽게 찾고 접을 수 있음). 너무 어렵지 않아야합니다. 이 방법은 로거의 일부가 될 수 있습니다. 그것은 당신에게 달려 있습니다. 그러나 그것은 시작하기에 좋은 장소처럼 보입니다.


+1, 공백은 좋은 방법입니다. success := CopyFile()아이디어 덕분에, 이것은 내 경우에 불필요한 코드 줄을 줄일 것입니다
PresleyDias

@ S.Robins 코드를 올바르게 읽었습니까? LogIfFileDoesNotExist복사 파일 이라는 방법 ?
João Portela

1
@ JoãoPortela 그래 ... 그것은 예쁘지 않고 단일 책임 원칙에 충실하지 않습니다. 이것은 내 머리 꼭대기에서 리팩토링하는 첫 번째 패스였으며 OP가 코드의 혼란을 줄이려는 목표를 충족시키는 데 도움이되는 것을 목표로했습니다. 아마도 방법의 이름을 잘못 선택했을 것입니다. 개선하기 위해 약간 조정하겠습니다. :)
S.Robins 2012

문제를 해결하는 데 시간이 걸린다는 것을 알게되어 반갑습니다 (+1).
João Portela

2

옵션 2의 아이디어는 최고라고 말할 수 있습니다. 그러나 나는 당신이 취하는 방향이 상황을 악화 시킨다고 생각합니다. 정수는 아무것도 의미하지 않습니다. 코드를 살펴보면 무언가가 기록되는 것을 볼 수 있지만 무엇을 알지 못합니다.

대신 나는 이런 식으로 뭔가를 할 것입니다 :

void logHelper(String phase, String message) {
   LogBook.Log(2, "[" + phase + "] :  [Action]: " + message);
}

메시지 구조는 유지되지만 코드는 유연합니다. 위상에 필요한 상수 문자열을 정의 할 수 있으며 위상 문자열로만 사용할 수 있습니다. 이를 통해 한 곳에서 실제 텍스트를 변경하고 모든 것에 영향을 줄 수 있습니다. 도우미 기능의 또 다른 이점은 중요한 텍스트가 코드와 함께 있고 (주석처럼) 로그 파일에만 중요한 텍스트는 추상화된다는 것입니다.

if (!FileExists(sOSdrive+'\Mapannotation.txt')) {
    if (CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False)) {
       logHelper(POSTGRESQL, 'copying Mapannotation.txt to '+ sOSdrive +'\ sucessful')
    } else {
       logHelper(POSTGRESQL, 'copying Mapannotation.txt to '+ sOSdrive +'\ Failed');
    }
}

이것은 귀하의 질문에서 언급 한 것이 아니지만 코드에 대해 알았습니다. 들여 쓰기가 일관되지 않습니다. 처음 사용할 begin때는 들여 쓰기가 아니라 두 번째로 들여 씁니다. 와 비슷한 일을 else합니다. 나는 이것이 로그 라인보다 훨씬 중요하다고 말합니다. 들여 쓰기가 일관되지 않으면 코드를 스캔하고 흐름을 따르기가 어렵습니다. 스캔 할 때 많은 반복적 인 로그 라인을 쉽게 필터링 할 수 있습니다.


1

이 라인을 따라 뭔가 어떻습니까 :

LogBook.NewEntry( 2,'POSTGRESQL INSTALLATION', 'copying Mapannotation.txt to '+sOSdrive);

if CopyFile(PChar(sTxtpath+'Mapannotation.txt'), PChar(sOSdrive+'\Mapannotation.txt'), False) then
    LogBook.Success()
else
    LogBook.Failed();

NewEntry () 메소드는 텍스트 라인 (적절한 항목 주위에 [&] 추가 포함)을 빌드하고 success () 또는 failure () 메소드가 호출 될 때까지 대기합니다. 'success'또는 'failure'를 입력 한 다음 행을 로그에 출력하십시오. 로그 항목이 성공 / 실패 이외의 다른 경우를위한 info ()와 같은 다른 메소드를 작성할 수도 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.