Zagwostka na etapie tworzenia komponentu do pobierania pliku po HTTPS.

0

Witam. Tak na szybko, bo życie w biegu. Wyedytowałem swój post i wklejam na szybko przed wyjściem do pracy popełniony moduł. Z obsługą wątków radzę sobie słabo Cóż - wieki nic nie kodowałem regularnie. Na oko wszystko tutaj działa jak należy. Ale chciałbym Was podpytać czy coś tutaj w kodzie można było by poprawić. Jak zrobić wznawianie ewentualne i czy są poważne błędy? I dodam że testowy plik po HTTPS można mieć stąd: https://speed.hetzner.de/100MB.bin

unit https_download;

interface

uses
  Windows, WinInet, Classes, SysUtils, httpsend, ssl_openssl;

type
  TProgressEvent = procedure(Sender : TObject; DownloadedBytes, TotalSize : DWORD) of object;
  THttpsDownload = class(TThread)
  private
    FUrl : string;
    FOutFile : file;
    FOutDir : string;
    FFileName : string;
    FUserAgent : string;
    FSynHttp : THttpSend;
    FTotalFileSize : DWORD;
    FDownloadedBytes : DWORD;
    FOnProgress : TProgressEvent;
  protected
    procedure DoProgress;
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
  published
    procedure Cancel;
    property FileSize : DWORD read FDownloadedBytes;
    property OnProgress : TProgressEvent read FOnProgress write FOnProgress;
    procedure DownloadFile(ArgUrl : string; ArgFileName : string; ArgOutDir : string = ''; ArgUserAgent : string = '');
  end;

implementation

const
  CR = #13;
  Https_Prefix = 'https:'#47#47;
  User_Agent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0';

procedure SMsg(Text : string);
begin
  MessageBox(GetActiveWindow, PChar(Text), PChar('Test'), MB_OK);
end;

function ExtractFileNameFromUrl(Url : string) : string;
var
  I : integer;
begin
  for I := Length(Url) downto 1 do
  begin
    if Copy(Url, I, 1) = '/' then
    begin
      Delete(Url, 1, I);
    end;
    Result := Url;
  end;
end;

function SimpleParse(StrBegin, StrEnd, Str : string) : string;
var
  B, E : integer;
begin
  Result := '';
  if StrBegin = '' then
  begin
    B := 1;
  end
  else
  begin
    B := Pos(StrBegin, Str);
  end;
  if B > 0 then
  begin
    Str := Copy(Str, B + Length(StrBegin), MaxInt);
    if StrEnd = '' then
    begin
      E := Length(Str) + 1;
    end
    else
    begin
      E := Pos(StrEnd, Str);
    end;
    if E > 0 then
    begin
      Result := Copy(Str, 1, E - 1);
    end;
  end;
end;

procedure THttpsDownload.Execute;
const
  BufferSize = 1024;
  Content_Length_Prefix = 'Content-Length: ';
var
  Tmp : integer;
  BufferLen : DWORD;
  HSession, HUrl : HInternet;
  Header, DestFileName : string;
  Buffer : array[1..BufferSize] of Byte;
begin
  FSynHttp := THttpSend.Create;
  with FSynHttp do
  begin
    Sock.CreateWithSSL(TSSLOpenSSL);
    Sock.SSLDoConnect;
    Protocol := '1.1';
    UserAgent := FUserAgent;
    HTTPMethod('HEAD', FUrl);
    Header := Headers.Text;
    Tmp := Pos(Content_Length_Prefix, Header);
    if Tmp > 0 then
    begin
      Tmp := Tmp + Length(Content_Length_Prefix);
      Header := Copy(Header, Tmp, MaxInt);
      Tmp := 1;
      while Header[Tmp] <> CR do
      begin
        Tmp := Tmp + 1;
      end;
      Delete(Header, Tmp, MaxInt);
      Val(Header, FTotalFileSize, Tmp);
    end;
    DestFileName := SimpleParse('Content-Disposition: attachment; filename="', '"', Headers.Text);
  end;
  if DestFileName <> '' then
  begin
    FFileName := DestFileName;
  end
  else
  begin
    DestFileName := ExtractFileNameFromUrl(FUrl);
    if DestFileName = '/' then
    begin
      DestFileName := FFileName;
    end;
  end;
  FreeAndNil(FSynHttp);
  FDownloadedBytes := 0;
  HSession := InternetOpen(PChar(User_Agent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  InternetConnect(hSession, PChar(FUrl), INTERNET_DEFAULT_HTTPS_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
  try
    HUrl := InternetOpenURL(hSession, PChar(FUrl), nil, 0, INTERNET_FLAG_DONT_CACHE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_RELOAD, 0);
    try
      AssignFile(FOutFile, FOutDir + DestFileName);
      Rewrite(FOutFile, 1);
      try
        repeat
          InternetReadFile(HUrl, @Buffer, SizeOf(Buffer), BufferLen);
          FDownloadedBytes := FDownloadedBytes + BufferLen;
          BlockWrite(FOutFile, Buffer, BufferLen);
          if Assigned(FOnProgress) then
          begin
            Synchronize(DoProgress);
          end;
        until BufferLen = 0;
      finally
        CloseFile(FOutFile);
      end;
    finally
      InternetCloseHandle(HUrl);
    end
  finally
    InternetCloseHandle(HSession);
  end;
end;

procedure THttpsDownload.DoProgress;
begin
  FOnProgress(Self, FDownloadedBytes, FTotalFileSize);
end;

constructor THttpsDownload.Create;
begin
  inherited Create(True);
  FDownloadedBytes := 0;
end;

destructor THttpsDownload.Destroy;
begin
  try
    CloseFile(FOutFile);
  finally
    if FSynHttp <> nil then
    begin
      FreeAndNil(FSynHttp);
    end;
  end;
end;

procedure THttpsDownload.Cancel;
begin
  Self.Suspend;
  Self.Free;
end;

procedure THttpsDownload.DownloadFile(ArgUrl : string; ArgFileName : string; ArgOutDir : string = ''; ArgUserAgent : string = '');
begin
  if Pos(Https_Prefix, ArgUrl) = 1 then
  begin
    FUrl := ArgUrl;
    FFileName := ArgFileName;
    if ArgOutDir = '' then
    begin
      FOutDir := '.\';
    end;
    if ArgUserAgent = '' then
    begin
      FUserAgent := User_Agent;
    end
    else
    begin
      FUserAgent := ArgUserAgent;
    end;
    Self.Resume;
  end;
end;

end.
1

Do wznawiania pobierania WinInet nada się na 99% procent, lecz pełnej pewności nie mam. Jest funkcja InternetSetFilePointer która będzie potrzebna przy wznawianiu oraz wysłanie headerów z RANGE
Po szybkim szukaniu u wujka, znalazlem taką stronę, możliwe, że Ci się przyda: https://www.clevercomponents.com/articles/article015/resuming.asp
Jeśli chodzi o twój kod to wyglada OK na pierwszy rzut oka, przypominam że modyfikując komponenty robimy to w głównym wątku dzięki TThread.Synchronize(proc)

P.S.Wcześniejszych wersji twojego posta nie byłem w stanie rozszyfrować, teraz kumam o co ci chodzilo
Pozdrawiam

1

tu if Copy(Url, I, 1) = '/' then za każdym razem tworzysz nowego stringa z 1 elementem - zrób po prostu if Url[I] = '/' then

0

Hej. Dziękuję Wam za odpwiedzi. Fakt że wcześniej nieco zawile napisałem. I abrakadaber ma racje też. Poza tym chyba w nadawaniu nazwy pliku przez wydobycie jej po ostatnim slaśhu machnąłem błąd. Bo jeśli zdarzyło by się tak że damy adres https://strona.net/ i tyle to funkcja zwróci pusty string lub bez ostatniego slasha zwróci "s" no ale to sytuacja nietyowa raczej ta funkcja ma pobrać plik z nazwą wyciągnietą z nagłówków albo podaną w parametrze. Ogólnie ten temat rozkminienia HTTPS mi ciążył od dswna ale bardzo rzadko siadam teraz by coś dla siebie pokodzić i początkowo jak zacząłem kodować to co wklejone tak przekombinować chciałem że szok :)

Ze wznawianiem też się zapoznam i ogolnie to co będzie wyłuskiwane ze stron i ich kodu HTML będzie robione z użyciem Synapse. A pobieranie po HTTP przytostowo z użyciem Simple TCP a po HTTPS tym kodem. Tylko tak z ciekawości może macie pojecie dlaczego Synapse przy pobieraniu z użyciem HTTPMethod('GET', Url); robi to o wiele wolniej niż wget czy Fire Fox? Bo testowałem sam rozwiązania i bez przyrostowego pobierania i samemu podczepiając się pod zdarzenie Sock. On... i są rożnice. Dopiero ten kod jak na te chwile dał zadowalający efekt.

3

Obiecałem zerknąć na ten kod, ale niestety nie miałem wcześniej czasu, dlatego dopiero teraz odpisuję. Kodu nie sprawdzę w praktyce i nie wiem dla której wersji Delphi jest ona przeznaczona, więc moją wypowiedź potraktuj jako zestaw wskazówek. :]


Pierwsza rzecz, taka która mi się od razu rzuca w oczy to formatowanie kodu. W losowej kolejności:

  • nie używasz prefiksu A dla argumentów (wszędzie),
  • nie korzystasz z grupowania argumentów tego samego typu, rozciągając nagłówki metod,
  • String piszesz małą literą, choć to zwykły typ danych (wszędzie),
  • ciągi znaków przekazujesz przez wartość, zamiast przez referencję jako const (wszędzie),
  • pomijasz puste nawiasy w metodach – wiem że to kwestia indywidualna, ale taka możliwość powinna zostać zdeprecjonowana, tak samo jak możliwość pominięcia średnika po ostatniej instrukcji w danym bloku kodu,
  • nie stosujesz UPPER_SNAKE_CASE dla identyfikatorów stałych (w metodzie Execute i te globalne),
  • rozciągasz kod stosując bloki begin end dla pojedynczych instrukcji (np. w metodzie SimpleParse),
  • stronisz od pustych linii rozdzielających logiczne fragmenty ciała metod (jw.),
  • używasz nic nie mówiących, jednoliterowych identyfikatorów dla zmiennych lokalnych (jw.),
  • używasz nic nie mówiących nazw metod (jw. oraz SMsg),
  • piszesz długie metody (np. Execute),
  • stosujesz przestarzałe instrukcje, zamiast korzystać z wysokopoziomowych klas (np. z TFileStream),
  • nadużywasz instrukcji Copy i Delete (np. w metodzie ExtractFileNameFromUrl),
  • bez potrzeby inicjalizujesz pola klasy, duplikująć wbudowane mechanizmy (np. w konstruktorze),
  • zdarzenia wołasz w sposób niezgodny z przyjętymi zasadami (np. OnProgress w Execute),
  • bezpodstawnie używasz FreeAndNil (np. w destruktorze),
  • niepotrzebnie robisz odstępy przed operatorem :.

No, to tyle na początek, teraz co nieco w związku z poprawkami kodu.


Masz dwa pola określające liczbę bajtów związanych z pobieraniem pliku – jedno przechowuje liczbę bajtów do pobrania, a drugie liczbę pobranych bajtów. Tyle że jedno ma w nazwie sufiks Size, a drugie Bytes. Pasuje to ujednolicić, ustalając po prostu nazwy TotalBytes i DownloadedBytes.


Metoda ExtractFileNameFromUrl robi praktycznie to samo co standardowa ExtractFileName, więc najprawdopodobniej możesz się jej pozbyć i skorzystać z tej istniejącej. Jednak nie mam dostępu do kodu biblioteki standardowej Delphi, więc nie mam pewności czy to przejdzie w przypadku URL.


Metoda SimpleParse nie wiadomo co robi, bo jej nazwa nic na ten temat nie mówi. Można by to wywnioskować po konstrukcji jej kodu oraz po nazwach zmiennych lokalnych, ale te są jednoliterowe i mówią jeszcze mniej. Domyślam się, że B oznacza Begin a E oznacza End, ale to moje domysły.

Poza tym kod tej metody można skrócić. Jeśli StrBegin jest pusty, to wykonywanie Pos nie ma sensu, bo ta funkcja w takim przypadku i tak niczego nie znajdzie. To samo jeśli chodzi o StrEnd w zagnieżdżonym bloku. Możesz skorzystać z funkcji PosEx, aby uniknąć kopiowania ciągu w drugim warunku.


Metodę Execute pasuje rozbić na mniejsze fragmenty. Jeden niech zajmie się określeniem wartości ciągu nagłówka, drugi wypełnieniem pól obiektu FSynHttp, kolejny niech zajmie się przygotowaniem ścieżek, a ostatnia niech zajmie się faktycznym pobieraniem pliku. Zaś metoda Execute niech woła wszystkie wymienione.


Metoda DoProgress nie jest zgodna z przyjętymi zasadami. A przyjęło się, że wszystkie metody o nazwach Do* służą do wywoływania zdarzeń z pól klasy, uprzednio sprawdzając, czy zdarzenie faktycznie jest do pola przypisane. U Ciebie metoda DoProgress nie sprawdza czy zdarzenie jest przypisane, a takie testowanie w zamian wykonywane jest w głównej pętli w metodzie Execute. Zmień ciało tej metody na takie:

procedure THttpsDownload.DoProgress();
begin
  if Assigned(FOnProgress) then
    FOnProgress(Self, FDownloadedBytes, FTotalBytes);
end;

i usuń warunek z głównej pętli metody Execute.


Konstruktor klasy jest zbędny, dlatego że FDownloadedBytes jest polem klasy, a te inicjalizowane są z automatu. Jeśli wartość True dla parametru konstruktora klasy bazowej jest wartością domyślną, to możesz śmiało wywalić swój konstruktor.


Destruktor niepotrzebnie sprawdza czy obiekt FSynHttp jest utworzony i jeśli tak, to niepotrzebnie używasz FreeAndNil do jego zwolnienia. Do tego właśnie służy metoda Free, aby nie rzucić wyjątku, jeśli obiekt nie istnieje. IMO wystarczy tyle:

destructor THttpsDownload.Destroy();
begin
  try
    CloseFile(FOutFile);
  finally
    FSynHttp.Free();
  end;
end;

Metoda DownloadFile odrzuca wszystkie adresy bez prefiksu Https_Prefix – dlaczego? Jeśli go nie ma to go po prostu dodaj i dla takiej wartości wykonaj dalszy kod. Najwyżej plik nie zostanie odnaleziony. Druga rzecz to warunki w tej metodzie – są całkowicie zbędne. Skoro wartość domyślna dwóch ostatnich argumentów i tak jest określona przez stałe, to użyj tych stałych w nagłówku metody – dzięki temu te warunki nie będą w ogóle potrzebne.

procedure THttpsDownload.DownloadFile(const AURL, AFileName: String; const AOutDir: String = '.\'; const AUserAgent: String = USER_AGENT);
begin
  if Pos(HTTPS_PREFIX, AURL) = 0 then
    FURL := HTTPS_PREFIX + AURL
  else
    FURL := AURL;

  FFileName := AFileName;
  FOutDir := AOutDir;
  FUserAgent := AUserAgent;

  Self.Resume();
end;

W powyższym przykładzie zmieniłem też nazwy argumentów. Te przeznaczone do przypisania do pól klasy powinny się różnić od nich tylko literką prefiksu (F dla pola i A dla argumentu, dalsze litery te same w obu).


To tyle zgrubsza, jeśli chodzi o ten kod. Nie szukałem jeszcze dokładniej, ale rzeczy do poprawienia jest więcej. No ale czasu nie mam na tyle, aby konkretnie wgryźć się w ten kod i wytknąć wszystkie niedociągnięcia. W każdym razie to na początek powinno wystarczyć. :]

0

Hej. Dzięki za wykład FP. Tak to jest jak pisze się rzadko i na przekór wielu woli się powracać do amatorskiego grzebania w mimo wszystko przestarzałym Delphi 7 i tak, bo... tak wolę i już :P Postaram się poprawić co się da. Co do sImpleParse to wyodrębnia tekst między nagłówkiem a końcem linii, kiedyś mi to tutaj ktoś podał jako przykład, chyba jeszcze Misiekd i tak zostało w paru projektach. Co do Extrakcji tego co po / to funkcja na Windows spodziewać się będzie raczej backslasha a nie slasha w ciągu, ale mogę się mylić. Ujednolicenie i poprawienie nazw czy poprawka formatowania to się zgodzę jak i z wieloma uwagami od FP.

A puste nawiasy nie stosuje na ogół, chyba że w PHP. no i tutaj pewna niekonsekwencja moja, bo pewne nawyki warto używać. Co do zmiany słowa string na małe robi to parser formatowania bo zmienia też słowa kluczowe takie jak np. begin, if, then, end i dlatego też tak traktuje "string" i "file" zgodnie z konwencją obsługi domyślnej przez dodatek GExperts. Co do założenia że ma to być obsługa HTTPS stąd to dziwne sprawdzenie, wtedy inicjujemy dodatkowy SSL tak jak to wygooglowałęm w jakimś przykładzie ze Stack Over Flow poza tym żeby kod był idealny i niezależny od protokołu to trzeba by dodać inne porty usług i odpowiednio wywoływać metody z WinInet. Jednak kajam się bo wieki nie kodowałem, nie siedzę w tym, grzebię raz na jakiś czas coś dla siebie dlatego tworzę na szybko gdy znajdę chwilę takie potworki mi zależało na ugryzieniu pobierania HTTPS tak by plik powstawał przyrostowo i bez spowolnień i to się udało. Teraz z Waszą pomocą z czasem kod zostanie zoptymalizowany i dopieszczony składniowo itd :)

0
olesio napisał(a):

Tak to jest jak pisze się rzadko i na przekór wielu woli się powracać do amatorskiego grzebania w mimo wszystko przestarzałym Delphi 7 i tak, bo... tak wolę i już :P

Tzn. jeśli z jakiegoś powodu wolisz lub wręcz musisz korzystać z Delphi 7, nie zmienia faktu, że możesz pisać ładny kod, zgodny z powszechnie przyjętymi zasadami. Jeśli się rzadko ma do czynienia z kodem to cóż – takie rzeczy ulatują z głowy i wychodzi się z wprawy.

Co do sImpleParse to wyodrębnia tekst między nagłówkiem a końcem linii […]

Jeśli ta metoda wyciąga fragment ciągu znaków to powinna mieć prefiks Extract i w dalszej części nazwę tego co ekstrahuje. Pamiętaj, że nazwy metod powinny się rozpoczynać od czasownika.

Co do Extrakcji tego co po / to funkcja na Windows spodziewać się będzie raczej backslasha a nie slasha w ciągu, ale mogę się mylić.

Windows w odróżnieniu od innych platform obsługuje oba separatory, ale domyślnym jest backslash.

Co do zmiany słowa string na małe robi to parser formatowania bo zmienia też słowa kluczowe takie jak np. begin, if, then, end i dlatego też tak traktuje "string" i "file" zgodnie z konwencją obsługi domyślnej przez dodatek GExperts.

Jeśli nie chcesz aby String był poprawiany przez narzędzia formatujące, to poszukaj opcji dotyczących słów kluczowych i wyklucz ten typ danych ze zbioru. W ogóle to nie mam pojęcia dlaczego od dawien dawna String mógł być uznawany za słowo kluczowe.

W każdym razie, w ustawieniach IDE powinna być możliwość kolorowania tego słówka w ten sam sposób co innych identyfikatorów. No ale nie pamietam jak to było w Delphi 7 – w Lazarusie taka opcja jest i mam ją wyłączoną:

string.png

Teraz z Waszą pomocą z czasem kod zostanie zoptymalizowany i dopieszczony składniowo itd :)

Najważniejsze aby działał prawidłowo – z formatowaniem można podziałać później.

Sam jednak wolę pisać kod w taki sposób, aby od początku dobrze działał i dobrze wyglądał – dzięki temu oszczędzam czas i nerwy. Natomiast z narzędzi formatujących nie korzystam nigdy i nie zamierzam korzystać. ;)

1

Miałem nie pisać bo to drobnostka ale temat wrócił więc mały OT odnośnie string

(...) możesz pisać ładny kod, zgodny z powszechnie przyjętymi zasadami.

@furious programming zasady się trochę zmieniły przynajmniej jeśli chodzi o Delphi i to spory czas temu. Od wprowadzenie Unicode jako domyślnego kodowania string pisany jest z małej litery.
https://www.embarcadero.com/images/dm/technical-papers/delphi-and-unicode-marco-cantu.pdf
Zgodnie z wytycznymi Embarcadero:

" In RAD Studio, string is an alias for UnicodeString."

W źródłowym dokumencie lepiej to widać, że chodzi o nazwę typu.
http://docwiki.embarcadero.com/RADStudio/Rio/en/String_Types_(Delphi)
I ta zasada została szeroko przyjęta bo wszędzie gdzie widzę string pisany jest z małej litery - sam też tak piszę ale głównie przez autouzupełnianie kodu.
Kilka przykładów, wszędzie string z małej:
https://www.oreilly.com/library/view/delphi-in-a/1565926595/re359.html
https://github.com/gabr42/FastMM4-MP/blob/master/FastMM4.pas
Nawet w informacjach IDE,
screenshot-20190530185621.png
i jest to zbudowane formatowanie producenta a nie z narzędzi firm trzecich.

Może się to podobać lub nie. Po wprowadzeniu sam na to zwróciłem uwagę ale przy przyzwyczaiłem i tyle.

0
Clarc napisał(a):

@furious programming zasady się trochę zmieniły przynajmniej jeśli chodzi o Delphi i to spory czas temu.

No nie, w sumie to zasady formatowania kodu się nie zmieniły – są takie jak były. Cały czas mam na myśli ogólne zasady formatowania całości kodu, dotyczące wszystkich pojęć, nie tylko identyfikatorów.

Od wprowadzenie Unicode jako domyślnego kodowania string pisany jest z małej litery.
https://www.embarcadero.com/images/dm/technical-papers/delphi-and-unicode-marco-cantu.pdf

Tak? No bo ja widzę coś zupełnie innego, jeśli chodzi o deklarację typu System.String:

type String = UnicodeString;
typedef UnicodeString String;

Zgodnie z wytycznymi Embarcadero:

" In RAD Studio, string is an alias for UnicodeString."

Najwyraźniej embarcadero uprawia hipokryzję jeśli chodzi o nazewnictwo typów danych, skoro typ zadeklarowany jest dużą literą, w swoim oficjalnym artykule pt. Object Pascal Style Guide informuje, że wszystkie identyfikatory (nie licząc jednoliterowych prefiksów np. dla pól klasy czy portowanych nagłówków) powinny być w stylu PascalCase:

3.0 Naming Conventions

Except for reserved words and directives, which are in all lowercase, all Pascal identifiers should use InfixCaps, which means the first letter should be a capital, and any embedded words in an identifier should be in caps, as well as any acronym that is embedded:

MyIdentifier
MyFTPClass

a wszędzie indziej nakazuje lub za pomocą funkcji środowiska przerabia ten identyfikator na lowercase.

Natomiast zanim potraktujesz czyjeś słowa jako argument, najpierw postaraj się je zrozumieć. Marco użył słowa string (małą literą) dziesiątki razy w podlinkowanym dokumencie, w zupełnie innym kontekście – nie do przedstawienia nazwy typu danych, a po prostu w jego dosłownym znaczeniu. No bo słówko string oznacza „łańcuch”, więc trudno jest pisać o różnych aspektach związanych z łańcuchami znaków w j. angielskim, jednocześnie nie używając słowa string właśnie.

I ta zasada została szeroko przyjęta bo wszędzie gdzie widzę string pisany jest z małej litery […]

No to do d**y że wszyscy tak piszą, ciągnąc bezpodstawnie tę zarazę, która nie służy absolutnie niczemu i łamie jednorodność formatowania kodu. Robienie czegoś bez jakichkolwiek sensownych i logicznych argumentów a tylko dlatego, że inni też tak robią, jest absolutnie bez sensu.

Może się to podobać lub nie.

Oczywiście że się nie podoba. Jeśli ustalamy ogólną zasadę dotyczącą formatowania identyfikatorów to stosujemy ją wszędzie. A jeśli ktoś te zasady łamie w imię ”kompatybilności wstecznej” czy ”solidarności” to trzeba takim praktykom się przeciwstawiać, co niniejszym czynię. ;)

Po wprowadzeniu sam na to zwróciłem uwagę ale przy przyzwyczaiłem i tyle.

Przykro mi, ale w takim przypadku czas się pozbyć złych nawyków i zacząć myśleć samodzielnie.

0

Jak pisał nie mam zamiaru ciągnąć OT. Angielski znam i rozróżniam string jako łańcuch i string jako typ danych w dokumencie.
screenshot-20190530194243.png

Robienie czegoś bez jakichkolwiek sensownych i logicznych argumentów a tylko dlatego, że inni też tak robią, jest absolutnie bez sensu.

A wykorzystanie systemu kontoli wersji ma sens jako argument kiedy wszyscy formatują kod według tych samych zasad, zazwyczaj automatycznie?
String i string może namieszać jeśli komuś w zespole nagle odwidzi się stosowanie przyjętych zasad.

1
Clarc napisał(a):

Angielski znam i rozróżniam string jako łańcuch i string jako typ danych w dokumencie.

Po tym zrzucie widzę, że autor tego kodu ma w poważaniu nie tylko formatowanie identyfikatorów, ale też ich sensowne i opisowe nazewnictwo. No wybaczcie, ale zmienne o nazwach w stylu str1 zalatują newbie.

Nie chcę i nie zamierzam tutaj wyjść na buca, ale gdyby ktokolwiek z nas zobaczył taki kod i jednocześnie nie wiedział kto jest jego autorem, to na 90% stwierdziłby, że pisał go początkujący programista.

A wykorzystanie systemu kontoli wersji ma sens jako argument kiedy wszyscy formatują kod według tych samych zasad, zazwyczaj automatycznie?

No dobrze, ale co ma system kontroli wersji do formatowania kodu? Nie rozumiem tego przykładu.

Poza tym jeśli wszyscy korzystają z automatycznego formatowania kodu, no to jak to jest? Nikt z tych ”wszystkich” już nie umie od razu pisać dobrego kodu i muszą się wspierać narzędziami formatującymi? Strach pomyśleć co by było, gdyby dać im narzędzie bez formattera. :/

String i string może namieszać jeśli komuś w zespole nagle odwidzi się stosowanie przyjętych zasad.

Jeśli komuś się ”odwidzi” stosowania do przyjętych praktyk, to jest to pierwszy sygnał dla pracodawcy do zwolnienia takiego pracownika. Bylejakość czy samowolka nie powinna być tolerowana, bo w dłuższej perspektywie czasu przełoży się na łatwość utrzymania projektu, a co za tym idzie na finanse firmy.

Całe szczęście Pascal jest niewrażliwy na wielkość znaków… oj ogromne to szczęście… Choć akurat w tym przypadku nie powinno być i trzebaby pisać String dużą literą – embarcadero zaliczyłoby samobójczy strzał w stopę.

0

No ale teraz to naprawdę przeginacie... to nie ma totalnie żadnego znaczenia, czy to string, czy String. Jak dzieci w piaskownicy "a mój tata kupił większy telewizor", "nieprawda, bo my mamy lepszy" :P

0

Formatowanie kodu nie jest rzeczą nieważną, bo wpływa na łatwość utrzymania oprogramowania.

Sama wielkość pierwszej literki jednego z wbudowanych typów danych większej szkody nie robi, jednak od takich rzeczy się zaczyna. Po jakimś czasie produkuje się syf a nie kod, którego nawet sam autor nie rozumie po tygodniu od jego napisania, a jego użytkownicy rwą włosy z głowy podczas analizy takich wspaniałości.

1 użytkowników online, w tym zalogowanych: 0, gości: 1