Kodumu ekibimdeki diğer programcılar tarafından daha okunabilir hale getirmem gerekiyor


11

Delphi'de bir proje çalışıyorum ve uygulama için bir yükleyici oluşturuyorum, üç ana bölüm var.

  1. PostgreSQL kurulum / kaldırma
  2. myapplication ( myapplication kurulumu nsi kullanılarak oluşturulur) yükleme / kaldırma.
  3. Komut dosyası aracılığıyla Postgres'de tablo oluşturma (toplu iş dosyaları).

Her şey düzgün ve sorunsuz çalışır, ancak bir şey başarısız olursa, LogToFileger'ı oluşturdum ki bu işlemin her adımında LogToFile
bu şekilde

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

Bu işlev LogToFileToFile.LogToFile(), içeriği bir dosyaya yazacaktır. Bu güzel çalışıyor, ama sorun, kodun her yerde kod çağrısı her yerde görmek gibi kodu okumak zor oldu gibi kod berbat olmasıdırLogToFileToFile.LogToFile()

Bir örnek

 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;

Gördüğünüz gibi, çok sayıda LogToFileToFile.LogToFile()çağrı var, daha
önce

 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)

Şimdi tüm kodumda durum böyle.
okumak zor.

herhangi biri bana LogToFile çağrıları karmaşa için güzel bir yol önerebilir?

sevmek

  1. 'LogToFileToFile.LogToFile () `çağrısını
    bu şekilde girintilemek

       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. Bunun gibi ayrı bir birimLogToFileger
    Bu birimin tüm LogToFile iletileri buna switch casebenzer

     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;
    

bu yüzden sadece gerektiği yerde LogToFilegingMyMessage (1) çağırabilirim.

Herkes bana bu şekilde LogToFileging için daha iyi ve daha temiz bir yaklaşım söyleyebilir?


5
Konunuzu cevaplamak için: Ekibinize anlayıp anlamadıklarını mı yoksa anlamsal mı olduğunu sormayı denediniz mi? Evet ise, o zaman "yeterli" okunabilir olmalıdır.
Spoike

@Spoike: ben sormak yaptı, her yerde logBook.log()karşılaşıldığı gibi okumak biraz zor .
PresleyDias

1'den 3'e kadar "iki ana bölüm var". Bence neden okunabilirlik hakkında bir sorunuz olduğunu anlıyorum. Tutarlılık için "düzenleyebilen" birini bulmak isteyebilirsiniz.
S.Lott

@ S.Lott ben 'iki' düzenledi 'üç' .. hata için ses
PresleyDias

Yanıtlar:


11

Günlüğe kaydetme eklediğinizde iki şey tanıttınız:

  1. Kod büyüdü, çünkü hemen hemen her eylem için, bu işlemi (veya başarısızlığını) kaydeden bir satır eklediniz
  2. Kütük hatlarının kendileri şişirilmiş ve okunabilirlikten uzaklaşıyor çünkü çok yer kaplıyorlar.

Bunların her birinin problemleri var, nispeten basit bir çözümü var:

  1. Kodu daha küçük işlevlere ayırın. Hata / başarı için tüm kopyalarınızın yanı sıra günlük iletilerini içeren dev bir işleve sahip olmak yerine, tam olarak bir dosyayı kopyalayacak ve kendi sonucunu kaydedecek bir "CopyFile" işlevi sunabilirsiniz. Bu şekilde ana kodunuz yalnızca CopyFile çağrılarından oluşur ve okunması kolay kalır.

  2. Kaydedicinizi daha akıllı hale getirebilirsiniz. Çok fazla tekrarlanan bilgiye sahip dev bir dize geçirmek yerine, işleri daha net hale getirecek numaralandırma değerlerini iletebilirsiniz. Veya LogFileCopy, LogDbInsert gibi daha özel Log () işlevlerini tanımlayabilirsiniz ... Ne kadar çok tekrarlarsanız yapın, bunu kendi işlevine dahil etmeyi düşünün.

(1) 'i takip ederseniz, şuna benzeyen bir kodunuz olabilir:

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

Ardından, CopyFile () öğenizin işlemi yapmak ve sonucunu günlüğe kaydetmek için birkaç kod satırına ihtiyacı vardır, böylece tüm kodlarınız kısa ve okunması kolaydır.

Farklı modüllerde bir arada kalması gereken bilgileri ayırdığınız için 2. yaklaşımınızdan uzak dururum. Sadece günlük kodlarınızla senkronizasyondan çıkmak için ana kodunuzu istiyorsunuz. Ancak LogMyMessage (5) 'e baktığınızda bunu asla bilemezsiniz.

GÜNCELLEME (yoruma verilen yanıt): Tam olarak kullandığınız dile aşina değilim, bu yüzden bu bölümün biraz uyarlanması gerekebilir. Tüm günlük mesajlarınız 3 şeyi tanımlar: bileşen, eylem, sonuç.

Sanırım bu MainMa'nın önerdiği şey. Gerçek dizgiyi iletmek yerine sabitleri tanımlayın (C / C ++ / C # 'de numaralandırma numaralandırma türünün bir parçası olurlar). Örneğin, bileşenler için şunlara sahip olabilirsiniz: DbInstall, AppFiles, Registry, Shortcuts ... Kodu küçülten her şey okumayı kolaylaştıracaktır.

Dilinizin değişken parametre geçişini desteklemesi de yardımcı olabilir, bunun mümkün olup olmadığından emin olmaz. Örneğin, eylem "FileCopy" ise, bu eylemin iki ek kullanıcı parametresi olmasını tanımlayabilirsiniz: dosya adı ve hedef dizin.

Dosya kopyalama satırlarınız şöyle görünecektir:

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

* Not, işlemin sonucunu ayrı bir yerel değişkente saklayabiliyorsanız ve bu değişkeni Log () 'a geçirebiliyorsanız, günlük satırını iki kez kopyalamanız / yapıştırmanız için bir neden yoktur.

Temayı burada görüyorsunuz, değil mi? Daha az tekrarlayan kod -> daha okunabilir kod.


+1, bana you could pass in enumerations values bu konuda daha fazla bilgi verebilir misiniz ?
PresleyDias

@PresleyDias: güncellenmiş yayın
DXM

tamam anladım, evet daha az tekrarlayan-> daha okunabilir kod
PresleyDias

2
+1 "Kodu daha küçük işlevlere ayırın." Bunu yeterince vurgulayamazsınız. Sadece çok fazla sorun ortadan kalkıyor.
Oliver Weiler

10

Görünüşe göre bir "LoggableAction" kavramını soyutlamanız gerekiyor. Örneğinizde, tüm çağrıların başarılı veya başarısız olduğunu belirtmek için bir bool döndürdüğü ve tek fark günlük iletisidir.

Delphi yazdığımdan bu yana yıllar geçti, bu yüzden c # esinlenen sahte kod ama böyle bir şey istediğinizi düşünürdüm

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

Sonra arama kodunuz olur

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

Fonksiyon işaretçileri için Delphi sözdizimini hatırlayamıyorum ama uygulama ayrıntıları ne olursa olsun, günlük rutin etrafında bir tür soyutlama aradığınız gibi görünüyor.


Muhtemelen bu şekilde kendim giderdim, ancak OP kodunun nasıl yapılandırıldığı hakkında daha fazla bilgi sahibi olmadan, bu yöntem işaretçilerin olası karışıklığını eklemeden, aramak için sadece birkaç ekstra yöntem tanımlamaktan daha iyi olup olmadığını söylemek zor. OP'nin bu tür şeyler hakkında ne bildikleri hakkında
S.Robins

+1, LoggableAction()bu güzel, doğrudan kontrol ve yazma yerine döndürülen değeri yazabilirsiniz.
PresleyDias

+100, harika bir cevap diliyorum, ama ben sadece bir cevap kabul edebilir :( .. Ben bir sonraki uygulamada bu öneriyi deneyeceğim, fikir için teşekkürler
PresleyDias

3

Olası bir yaklaşım, sabitleri kullanarak kodu azaltmaktır.

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');

olacaktı:

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)

Ekrandaki karakter sayısını sayarken daha iyi bir günlük koduna / diğer kod oranına sahiptir.

Bu, sorunuzun 2. maddesinde önerdiğiniz şeye yakın, ancak şu ana kadar gitmeyeceğim: Log(9257)Açıkçası daha kısa Log(2, SqlInstal, Action, CopyMapSuccess, sOSdrive), ama aynı zamanda okunması oldukça zor. 9257 nedir? Başarılı mı? Aksiyon? SQL ile ilgili mi? Son on yıl boyunca bu kod tabanı üzerinde çalışıyorsanız, bu sayıları ezbere öğreneceksiniz (bir mantık varsa, yani 9xxx başarı kodlarıysa, x2xx SQL ile ilişkilidir, vb.), Ancak yeni bir geliştirici için kod tabanı, kısa kodlar bir kabus olacak.

İki yaklaşımı karıştırarak daha ileri gidebilirsiniz: tek bir sabit kullanın. Şahsen bunu yapmam. Sabitleriniz büyüyecek:

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

veya sabitler kısa kalır, ancak çok açık değildir:

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?

Bunun da iki dezavantajı var. Zorunda olacaksın:

  • Günlük bilgilerini ilgili sabitleriyle ilişkilendiren ayrı bir liste tutun. Tek bir sabit ile hızlı büyür.

  • Ekibinizde tek bir formatı zorlamanın bir yolunu bulun. Örneğin T2SSQ, biri yazmak yerine, ne yazmaya karar verecek ST2SQL?


+1, temiz logçağrı için, ama bana anlamadım daha fazla açıklayabilir misiniz Log(2, SqlInstal, Action, CopyMapFailure, sOSdrive), demek istediğim SqlInstalgibi benim tanımlanmış değişken olacak SqlInstal:=[POSTGRESQL INSTALLATION] ?
PresleyDias

@PresleyDias: SqlInstalherhangi bir şey olabilir, örneğin bir değer 3. Ardından, Log()bu değer [POSTGRESQL INSTALLATION], günlük iletisinin diğer bölümleriyle birleştirilmeden önce etkin bir şekilde dönüştürülecektir .
Arseni Mourzenko

single format in your teamiyi / harika bir seçenektir
PresleyDias

3

Tüm dağınık görünümlü şeyleri işlemek için bir dizi küçük işlevi çıkarmayı deneyin. Hepsi tek bir yerde kolayca yapılabilecek çok sayıda tekrarlanan kod var. Örneğin:

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;

İşin püf noktası, kodunuzdaki herhangi bir çoğaltmaya bakmak ve onu kaldırmanın yollarını bulmaktır. Çok fazla boşluk kullanın ve başlangıcını / sonunu avantajınıza kullanın (daha fazla boşluk ve kod bloklarını bulmak / katlamak kolaydır). Gerçekten çok zor olmamalı. Bu yöntemler kaydedicinizin bir parçası olabilir ... gerçekten size kalmış. Ama başlamak için iyi bir yer gibi görünüyor.


+1, beyaz alanlar güzel bir yol .. success := CopyFile()fikir için teşekkürler, bu benim durumumda bazı gereksiz kod satırlarını azaltacaktır
PresleyDias

@ S.Robins kodunuzu doğru okudum mu? LogIfFileDoesNotExistkopya adında yönteminiz ?
João Portela

1
@ JoãoPortela Evet ... çok hoş değil ve tek sorumluluk ilkesine bağlı kalmıyor. Unutmayın ki bu, başımın üst kısmından yeniden düzenleme yapan bir ilk geçişti ve OP'nin kodundaki karışıklığın bir kısmını azaltma amacını yerine getirmesine yardımcı olmayı amaçladı. Muhtemelen ilk başta yöntem için kötü bir isim seçimi. İyileştirmek için biraz ayarlayacağım. :)
S.Robins

bu sorunu çözmek için zaman ayırdığınızı görmek güzel, +1.
João Portela

2

Seçenek 2'nin arkasındaki fikrin en iyisi olduğunu söyleyebilirim. Ancak, bence bu yönü gittikçe daha da kötüleştiriyor. Tam sayı hiçbir şey ifade etmez. Koda baktığınızda, bir şeyin günlüğe kaydedildiğini göreceksiniz, ancak ne olduğunu bilmiyorsunuz.

Bunun yerine böyle bir şey yapardım:

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

Bu mesaj yapısını korur ancak kodunuzun esnek olmasını sağlar. Sabit dizeleri fazlar için gerektiği gibi tanımlayabilir ve bunları yalnızca faz parametresi olarak kullanabilirsiniz. Bu, gerçek metinde tek bir yerde değişiklik yapabilmenizi ve her şeyi etkileyebilmenizi sağlar. Yardımcı işlevinin bir diğer yararı da, önemli metnin kodla birlikte olması (yorum gibi), ancak günlük dosyası için önemli olan metnin soyutlanmasıdır.

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');
    }
}

Bu, sorunuzda bahsettiğiniz bir şey değil, ancak kodunuzu fark ettim. Girintiniz tutarlı değil. İlk kullandığınızda begingirintili değil, ikinci kez kullanıldığında. Benzer bir şey yapıyorsun else. Bunun kütük hatlarından çok daha önemli olduğunu söyleyebilirim. Girinti tutarlı olmadığında, kodu taramayı ve akışı takip etmeyi zorlaştırır. Tarama sırasında çok sayıda tekrarlanan günlük satırının filtrelenmesi kolaydır.


1

Bu çizgi boyunca bir şeye ne dersiniz:

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 () yöntemi, metin satırını (uygun girişlerin etrafına [&] eklenmesi de dahil) oluşturur ve bunu 'başarılı' veya 'fail' yazın ve satırı günlüğe kaydedin. Günlük girişinin başarı / başarısızlıktan başka bir şey için olduğu zaman info () gibi başka yöntemler de yapabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.