C++ och dess framtid att programmera minnessäkert - Hur går utvecklingen?

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Samma invändningar återkommer igen och igen: det kommer ta för lång tid och det kommer vara jobbigt när man ändrar i koden.

Ja och så är det, i vad du än gör måste du väga fördelar mot nackdelar. Allt bär med sig fördelar och nackdelar och de måste man väga mot varandra.
Det här är min kritik mot enhetstester, de tar för mycket tid att skriva, tar inte allt och väldigt mycket går smidigare att testa på annat sätt. Igår kväll när jag satt och trådade upp metoden (och en annan) tog det kanske 3-4 timmar. Hade jag fått skriva test hade det troligen tagit det femdubbla och jag hade haft mycket mer kod att underhålla. Det är inte den enda metoden, finns 7 till där två av dem är mycket komplicerade. Började med de enklaste.
Har inte mer än några timmar fyra till fem dagar i veckan på kvällen, endast för att tråda dessa totalt 8 metoder hade kanske tagit nästan ett halvår. Istället för knappt två veckor.

Jag ser inte hur ett test kunnat lösa eventuellt problem heller.

Skrivet av Ingetledigtnamn:

Då undrar jag om du över huvud taget utför någon testning av dina gjorda ändringar. Det kommer väl vara ännu jobbigare att sätta upp systemtester för att testa dessa ändringar? Eller kör du ditt grep++-program med lite olika inputs och är nöjd om det inte kraschar? Med testning på den nivån vet du ju inte ens om den ändrade koden är körd.

Jag har testat på mängder med kod och testar kod återanvänds med. I exemplet finns det två "table" klasser. De är lite som std::vector, kan användas till massor av saker. Fungerar de på ett ställe så borde de fungera på andra ställen med. De här körs i test och det är ju samma kod

Skrivet av Ingetledigtnamn:

Hur klarar ni er med testning på den nivån? Vad har du för folk i ditt team? Alla kan inte ha samma Rain Man-lika kvalitéer som du. Tar ni aldrig in nya? Eller får de hålla sig i sandlådan i två år och göra alla misstag man kan göra innan de släpps lös i produktionskoden?

Angående den kod jag klistrade in så är det eget hobby projekt, på jobbet är det andra
Räkna information i källkodsfiler är inte så avancerat även om det växt en del, mycket mer än vad jag tänkte från början.

Permalänk
Medlem
Skrivet av klk:

Ja och så är det, i vad du än gör måste du väga fördelar mot nackdelar. Allt bär med sig fördelar och nackdelar och de måste man väga mot varandra.
Det här är min kritik mot enhetstester, de tar för mycket tid att skriva, tar inte allt och väldigt mycket går smidigare att testa på annat sätt.

Tidigare hävdade du att enhetstester var för osäkra och nu tar dom för mycket tid att skriva(tolkar jag som lathet) och är smidigare att testa på annat sätt ... du har fortfarande inte visat något om hur du testar eller ens uppnår någon form av test-täckning.

Skrivet av klk:

Jag har testat på mängder med kod och testar kod återanvänds med. I exemplet finns det två "table" klasser.
...
De här körs i test och det är ju samma kod

... så hur testar du table-klasserna?

Skrivet av klk:

Angående den kod jag klistrade in så är det eget hobby projekt, på jobbet är det andra

Enligt din tidigare kommentar så har hobbykod högre kvalitet än företagskod ... det lämnar inte mycket hopp för din arbetsgivare. För att citera:

Skrivet av klk:

...
Hobbykod brukar vara av högre kvalitet än ute hos företag, folk tenderar bara att göra det som de blir tillsagda att göra. Hobbykod är något man själv vårdar och då sköts det bättre.
...

Permalänk
Medlem
Skrivet av orp:

Enligt din tidigare kommentar så har hobbykod högre kvalitet än företagskod ... det lämnar inte mycket hopp för din arbetsgivare.

Jag vet inte hur du tänker men mitt lilla hobbyprojekt är i klass med de snabbaste andra sökverktygen förutom att det kan en hel del till. "ripgrep" räknas till att vara snabbast av dem alla vad jag sett, funktionalitetsmässigt har alla stora brister.

förlåt skrytet men så svårt är det inte om man bara kan ta sig ur sin bubbla

Permalänk
Medlem
Skrivet av klk:

Jag vet inte hur du tänker men mitt lilla hobbyprojekt är i klass med de snabbaste andra sökverktygen förutom att det kan en hel del till. "ripgrep" räknas till att vara snabbast av dem alla vad jag sett, funktionalitetsmässigt har alla stora brister.

förlåt skrytet men så svårt är det inte om man bara kan ta sig ur sin bubbla

Lika snabbt som ripgrep utan ripgreps funktionalitet...

Permalänk
Medlem
Skrivet av orp:

Lika snabbt som ripgrep utan ripgreps funktionalitet...

tvärtom, mer funktionalitet

Finns massor av sökverktyg som endast wrappat regex sökningar. De kan inte så mycket mer än så

Permalänk
Medlem
Skrivet av klk:

tvärtom, mer funktionalitet

Finns massor av sökverktyg som endast wrappat regex sökningar. De kan inte så mycket mer än så

Så vilka arkivformat stödjer du?

Hur hanterar du search and replace?
Hur hanterar du only-match?
Hur hanterar du invert-match?
Hur hanterar du case-insensitivity(case sensitive, non case sensitive, smart case)?
Vilka regex-motorer stödjer du?

Permalänk
Medlem

Vi behöver inte spekulera. https://burntsushi.net/ripgrep/ har en benchmark som kan laddas ner, bara lägg till ditt verktyg så ser vi Jag har inte kollat hur den verifierar att verktygen ger samma output, men det står säkert någonstans.

Permalänk
Medlem
Skrivet av orp:

Så vilka arkivformat stödjer du?

Hur hanterar du search and replace?
Hur hanterar du only-match?
Hur hanterar du invert-match?
Hur hanterar du case-insensitivity(case sensitive, non case sensitive, smart case)?
Vilka regex-motorer stödjer du?

Sökmässigt tror jag det mesta, har inte sökning i zipfiler och replace vet jag inte om jag lägger till, inte så svårt men riskabelt om man inte har tid för support

Men fokus är faktiskt inte att söka i kod utan målet är KANBAN liknande verktyg
Lagt en del tid på att kunna styla resultat och ha olika teman

Det jag tycker andra verktyg brister i är hur de kan presentera resultat och filtrera samt integration med utvecklingsmiljöer. Också hur återkommande sökningar kan göras, blir för mycket pill varje gång man skall söka

använde boost som regex när det skall köras men har också egen söklogik

Permalänk
Medlem
Skrivet av klk:

Sökmässigt tror jag det mesta, har inte sökning i zipfiler och replace vet jag inte om jag lägger till, inte så svårt men riskabelt om man inte har tid för support

Men fokus är faktiskt inte att söka i kod utan målet är KANBAN liknande verktyg
Lagt en del tid på att kunna styla resultat och ha olika teman

Det jag tycker andra verktyg brister i är hur de kan presentera resultat och filtrera samt integration med utvecklingsmiljöer. Också hur återkommande sökningar kan göras, blir för mycket pill varje gång man skall söka
<Uppladdad bildlänk>

använde boost som regex när det skall köras men har också egen söklogik

Du har alltså inte implementerat något i närheten av ripgrep dvs du jämför en simpel textsökning med ripgrep. Jag förstår inte hur du tror att jag inte kommer syna din bluff om sådant här. Jag chansar på att du har hört ThePrimeagen hylla ripgrep och tänkte "Det låter häftigt om jag säger att skrivit en egen implementation av ripgrep som är likvärdig" ...

Permalänk
Medlem
Skrivet av orp:

Du har alltså inte implementerat något i närheten av ripgrep dvs du jämför en simpel textsökning med ripgrep. Jag förstår inte hur du tror att jag inte kommer syna din bluff om sådant här. Jag chansar på att du har hört ThePrimeagen hylla ripgrep och tänkte "Det låter häftigt om jag säger att skrivit en egen implementation av ripgrep som är likvärdig" ...

Det är inte samma typ av program, har alltid stört mig på de sökverktyg som finns i olika utvecklingsmiljöer för de säker nästan alltid i all kod. Har man då mycket kod i projektet så blir det jobbigt, lite som LSPer också, det fungerar i det lilla men blir det större så fungerar det inte lika bra.

Men det stämmer, har fräckheten att göra något själv och till och med nämna att det finns saker där som inte finns i ripgrep
Tänk att det finns idioter som skriver egna program.

Permalänk
Medlem
Skrivet av pine-orange:

Vi behöver inte spekulera. https://burntsushi.net/ripgrep/ har en benchmark som kan laddas ner, bara lägg till ditt verktyg så ser vi Jag har inte kollat hur den verifierar att verktygen ger samma output, men det står säkert någonstans.

Hur "snabba" sökverktygen är är nära nog helt beroende av hur snabb SSD man har om de kan skala till fler trådar. Kör man bara en tråd kommer verktyget vara långsammare. Har filer lästs och ligger i cache (operativsystemets cache) är förmodligen även enkel-trådade sökverktyg tillräckligt.

Har "bara" testat på runt 4 miljoner rader kod men även där är det inga större problem. Skall se om jag kan hitta någon jätte och testa på.

Permalänk
Medlem
Skrivet av klk:

Det är inte samma typ av program, har alltid stört mig på de sökverktyg som finns i olika utvecklingsmiljöer för de säker nästan alltid i all kod. Har man då mycket kod i projektet så blir det jobbigt, lite som LSPer också, det fungerar i det lilla men blir det större så fungerar det inte lika bra.

Men det stämmer, har fräckheten att göra något själv och till och med nämna att det finns saker där som inte finns i ripgrep
Tänk att det finns idioter som skriver egna program.

Det är inte idioter som skriver egna program.

Det är idioter som skriver egna program jämför dom med respekterade program och säger att dom erbjuder mer funktionalitet med likvärdig prestanda och hävdar att det respekterade programmet har stora brister (och därmed insinuerar att ens eget program inte har liknande brister) och i samma veva säger "ursäkta skrytet" (precis som man utfört ett stordåd) när man blev konfronterad om programmets kodkvalitet efter att man redan gjort ett korkat uttalande om att hobbyprojekt har högre kodkvalitet än företagskod... det är idiotiskt.

Utöver det så har jag inte upplevt några problem med mina LSPer.

Permalänk
Datavetare
Skrivet av klk:

Menar du att man skall skriva separata test för varje metod? Det tror jag inte va, då blir man ju aldrig klar

Hur skulle du skriva test för följande kod (alltså mer ett resonemang, skriv ingen kod för den är svår att skriva test för), satt precis och gjorde den så det kanske är någon bugg

/** --------------------------------------------------------------------------- * @brief Updates the pattern list for files in the cache using regex patterns and multithreading. * * This method processes a list of regex patterns and applies them to the files stored in the cache. * It generates a list of lines in each file where the patterns are found and stores the results * in the "file-linelist" cache table. The method uses multithreading to process files in parallel. * * @param vectorRegexPatterns A vector of pairs containing regex patterns and their names. * The vector must not be empty. * @param argumentsList Arguments for pattern processing (e.g., segment specification, max lines) * @param iThreadCount Number of threads to use (0 = auto-detect) * @return A pair containing: * - `bool`: `true` if the operation was successful, `false` otherwise. * - `std::string`: An empty string on success, or an error message on failure. * * @pre The `vectorRegexPatterns` must not be empty. * @post The "file-linelist" cache table is updated with the lines where the patterns are found. * * @note COMMAND_ListLinesWithPattern must be thread-safe. */ std::pair<bool, std::string> CDocument::FILE_UpdatePatternList(const std::vector<std::pair<boost::regex, std::string>>& vectorRegexPatterns, const gd::argument::shared::arguments& argumentsList, int iThreadCount) { assert(vectorRegexPatterns.empty() == false); // Ensure the regex pattern list is not empty using namespace gd::table; auto* ptableFile = CACHE_Get("file"); // Retrieve the "file" cache table auto* ptableLineList = CACHE_Get("file-linelist", true); // Ensure the "file-linelist" table is in cache assert(ptableFile != nullptr); assert(ptableLineList != nullptr); std::string_view stringSegment; if( argumentsList.exists("segment") == true ) { stringSegment = argumentsList["segment"].as_string_view(); } // Get the segment (code, comment, string) to search in uint64_t uMax = argumentsList["max"].as_uint64(); // Get the maximum number of lines to be printed auto uFileCount = ptableFile->get_row_count(); // Total number of files to process // ## Thread synchronization variables std::atomic<uint64_t> uAtomicFileIndex(0); // Current file being processed std::atomic<uint64_t> uAtomicProcessedCount(0); // Count of processed files std::atomic<uint64_t> uAtomicTotalLines(0); // Total lines found across all threads std::mutex mutexProgress; // Mutex to protect progress updates std::mutex mutexLineList; // Mutex to protect ptableLineList access std::vector<std::string> vectorErrors; // Collect errors from all threads std::mutex mutexErrors; // Mutex to protect access to vectorErrors // ## Worker function to process files in parallel ......................... auto process_ = [&](int iThreadId) -> void { // Create thread-local table for collecting results detail::columns* pcolumnsThread = new detail::columns{}; ptableLineList->to_columns( *pcolumnsThread ); std::unique_ptr<table> ptableLineListLocal = std::make_unique<table>(pcolumnsThread, 10, ptableLineList->get_flags(), 10); // Create local table with 10 rows pre-allocated while( true ) { uint64_t uRowIndex = uAtomicFileIndex.fetch_add(1); // get thread safe current index and increment it if(uRowIndex >= uFileCount) { break; } try { // STEP 1: Get file info (ptableFile is read-only so no mutex needed) auto stringFolder = ptableFile->cell_get_variant_view(uRowIndex, "folder").as_string(); auto stringFilename = ptableFile->cell_get_variant_view(uRowIndex, "filename").as_string(); // STEP 2: Build full file path gd::file::path pathFile(stringFolder); pathFile += stringFilename; std::string stringFile = pathFile.string(); auto uKey = ptableFile->cell_get_variant_view(uRowIndex, "key").as_uint64(); // STEP 3: Find lines with regex patterns gd::argument::shared::arguments arguments_({{"source", stringFile}, {"file-key", uKey}}); if( stringSegment.empty() == false ) arguments_.set("segment", stringSegment.data()); // Set the segment (code, comment, string) to search in auto result_ = COMMAND_ListLinesWithPattern(arguments_, vectorRegexPatterns, ptableLineListLocal.get()); // Find lines with regex patterns and update the local table if(result_.first == false) { std::lock_guard<std::mutex> lockErrors(mutexErrors); vectorErrors.push_back("File: " + stringFile + " - " + result_.second); uint64_t uProcessed = uAtomicProcessedCount.fetch_add(1) + 1; // Update progress even on failure if(uProcessed % 10 == 0) { std::lock_guard<std::mutex> lockProgress(mutexProgress); uint64_t uPercent = (uProcessed * 100) / uFileCount; MESSAGE_Progress("", {{"percent", uPercent}, {"label", "Find in files"}, {"sticky", true}}); } continue; // Skip to next file on error } // STEP 4: Append results to main table (FAST operation - mutex needed for thread safety) { std::lock_guard<std::mutex> lockLineList(mutexLineList); ptableLineList->append(ptableLineListLocal.get()); // Append the results from the local table to the main table // Update total line count and check if we've exceeded the maximum uint64_t uCurrentLines = uAtomicTotalLines.fetch_add(ptableLineListLocal->get_row_count()) + ptableLineListLocal->get_row_count(); if( uCurrentLines > uMax ) { uAtomicFileIndex.store(uFileCount); // Signal other threads to stop by setting file index to max } } ptableLineListLocal->row_clear(); // Clear local table rows for next iteration uint64_t uProcessed = uAtomicProcessedCount.fetch_add(1) + 1; // Update progress (thread-safe) if(uProcessed % 10 == 0) // Show progress every 10 files { std::lock_guard<std::mutex> lockProgress(mutexProgress); uint64_t uPercent = (uProcessed * 100) / uFileCount; MESSAGE_Progress("", {{"percent", uPercent}, {"label", "Find in files"}, {"sticky", true}}); } } catch(const std::exception& exception_) { std::lock_guard<std::mutex> lockErrors(mutexErrors); vectorErrors.push_back(std::string("Thread ") + std::to_string(iThreadId) + " error: " + exception_.what()); } } }; // ## Prepare and run threads .............................................. if( iThreadCount <= 0 ) { iThreadCount = std::thread::hardware_concurrency(); } // Use hardware concurrency if no thread count is specified if(iThreadCount <= 0) { iThreadCount = 1; } // Fallback to single thread if hardware_concurrency returns 0 if( iThreadCount > 8 ) { iThreadCount = 8; } // Limit to 8 threads for performance and resource management if( ptableFile->size() < iThreadCount ) { iThreadCount = (int)ptableFile->size(); } // Limit threads to number of files // Create and launch worker threads std::vector<std::thread> vectorPatternThread; vectorPatternThread.reserve(iThreadCount); for(int i = 0; i < iThreadCount; ++i) { vectorPatternThread.emplace_back(process_, i); } // Wait for all threads to complete for(auto& threadWorker : vectorPatternThread) { threadWorker.join(); } MESSAGE_Progress("", {{"clear", true}}); // Clear progress message // ### Handle any collected errors if(!vectorErrors.empty()) { for(const auto& stringError : vectorErrors) { ERROR_Add(stringError); } } return {true, ""}; }

Dold text

Måste fråga, du har en ultra-wide skärm va?
Sitter själv på en 5120x2160 skärm och det behövs när man ska läsa kod som passerar >200 tecken per rad...

Din egentliga fråga var ju "hur man kan testa detta".

Givet signaturen och det faktum att denna funktion i praktiken jobbar med globala data gör det allt annat än lätt att skriva bra och framförallt blir det svårt att skriva väldigt korta/enkla unit-tester. Man kommer behöva sätta upp en del mocks för att göra någon vettig testning alls.

std::pair<bool, std::string> CDocument::FILE_UpdatePatternList ( const std::vector<std::pair<boost::regex, std::string>>& vectorRegexPatterns, <--- this is part of input const gd::argument::shared::arguments& argumentsList, // <--- not at all obvious what keys that are relevant... int iThreadCount // <--- should probably be handled via environment / config ) { using namespace gd::table; auto* ptableFile = CACHE_Get("file"); // <---- this is the ACTUAL input ...

Är än mer dunkelt vad som egentligen är utdata från denna funktion. Att få en bool/string par hjälper lite, att veta vad som faktiskt output är hade hjälpt mycket...

Men rent principiellt är det ju här inte svårare än att sätta upp ett gäng fall med olika input. Endera på fil som en hjälpfunktion lägger in i cache:en innan varje test eller för små tester är det alltid enklast att bara ha litteraler.

Typ

test_something_successful() { set_cache_content(content_a); auto [success, error] = FILE_UpdatePatternList(...); auto actual_output = get_actual_output_from_cache(); assert_true(success); assert_equal("whatever the output should be", actual_output); } test_something_foobar() { set_cache_content(content_b); auto [success, error] = FILE_UpdatePatternList(...); assert_false(success); assert_equal("whatever the output should be", error); } ... etc

Ett typiskt unit-test i min värld har en cyklomatisk kodkomplexiteet på 1 och består av mellan 3 till ~10 rader. De ska vara superenkla att skriva och ska helst testa _en_ sak (som logiskt kan vara "success är false, same error är XYX" i detta fall).

Det är kod som ska skrivas, men fattar inte hur du kan få det till att det på sikt skulle vara snabbare att testa alla tänkbara kombos genom att manuellt köra programmet. Det blir ju skitmycket tid om/när man behöver göra något där det inte är helt glasklart exakt vilka delar som påverkas.

Skrivet av klk:

Hur "snabba" sökverktygen är är nära nog helt beroende av hur snabb SSD man har om de kan skala till fler trådar. Kör man bara en tråd kommer verktyget vara långsammare. Har filer lästs och ligger i cache (operativsystemets cache) är förmodligen även enkel-trådade sökverktyg tillräckligt.

Har "bara" testat på runt 4 miljoner rader kod men även där är det inga större problem. Skall se om jag kan hitta någon jätte och testa på.

Du kan alltid testa på Linux-kärnan. Den passerade 40 miljoner rader kod för en tid sedan.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

Måste fråga, du har en ultra-wide skärm va?
Sitter själv på en 5120x2160 skärm och det behövs när man ska läsa kod som passerar >200 tecken per rad...

kort svar
Har tre stycken 4K 32" skärmar, en står på höjden och de andra i bredd

Passar på och ger ett tips för att skona nacken, utvecklare sitter länge vid skärmen. Nacken håller många år men inte hur många år som helst.
Se till att ha skärmen i ögonhöjd eller där man tittar "mest" och jobba i första hand med att titta rakt fram. Viktigt med bra ryggstöd på stolen och så att man då och då kan vila huvudet ryggstödets nackskydd, helst kunna jobba och ha huvudet vilande.

Får man ont i fingrarna som carpal tunnelsyndrom och liknande, kolla så det inte är nacken som är problemet. Sjukvården missar nästan alltid det och man kan vara symptomfri i nacken men det värker i fingrarna.

Svarar sedan

Permalänk
Medlem
Skrivet av orp:

Det är inte idioter som skriver egna program.

Men det är faktiskt idiotiskt, om man tror det går att skriva program i syfte att det skall bli intressant för andra så är man en idiot. Enda anledningen att göra något sådant är att man tycker det är kul och då måste de som skriver programmet anpassa efter vad de tycker är roligt.

Otroligt svårt att marknadsföra något och finns det bara det minsta annat som är poppis så kan man göra något som är dubbelt så bra eller mer, det går ändå inte. Ofta för att folk som lärt sig använda något är vana vid det, de byter inte och söks det efter verktyg eller annat så tar i princip alla det vanligaste.

Ett exempel vi pratat om i tråden är det rustprojektet där de skriver om sqlite (turso) i rust. De kanske kan klara och få fart på det men det beror på att det är så många andra rustutvecklare som "säljer", hela rust communityn har lyckats väldigt bra med att stötta varandra. Bara att få villiga testare är guld värt för någon hobbyutvecklare.
Om sqlite skrivits om i något annat språk hade hela det projektet troligen hamnat i glömska.

I nästan alla typer av sådana här projekt är det en eldsjäl men i "sqlite (turso)" verkar det som en grupp håller på, kanske har de fått viss finansering.

Skrivet av orp:

programmets kodkvalitet efter att man redan gjort ett korkat uttalande om att hobbyprojekt har högre kodkvalitet än företagskod...

Förstår inte varifrån du fått att företag har bra kodkvalitet, var har du sett det?

Kan ta ett annat exempel raddebugger.
Det projektet ligger nu på c.a. 180 000 rader (rensat från genererad kod mm) och Ryan som skriver koden verkar ha gjort det mesta. Gissar att han har lön från Epic för det står att Epic har copyright. Ser ut som att att han producerat denna mängd kod på lite drygt ett år. Även om det är C kod så är 180 000 rader produktions kod på drygt ett år kopiösa mängder och en kvalitetsstämpel. För varje rad i produktion gör ofta utvecklare tre eller fyra totalt men det raderas och skrivs om så färdig kod är en fjärdedel. Ryan är troligen en unicorn som utvecklare och då kan han tänka mer rätt. Och för att ha den hastigheten kan han tekniker som gör honom snabb och han har säkert väldigt bra hjälp i att få koden testad. Tror bara det är C programmerare som kan komma upp i de hastigheterna och samtidigt ha kontroll på koden.

Det är förmodligen minimalt med enhettester, endast det nödvändigaste. Mycket funktioner att pröva annars och han skulle ha haft stora problem

Hade Ryan gjort det här som ett hobby projekt hade koden aldrig tagits fram. Spelar ingen roll om han lyckats skriva exakt samma samma utanför Epic och det beror på att det är så mycket annat för att få ut mjukvara. Men utan lön måste det mer själ och det kostar på mentalt att misslyckas, något man inte känner av om det trillar in en lön. Kvaliteten är därför naturligt högre men man måste ta genvägar

Permalänk
Medlem
Skrivet av Yoshman:

Din egentliga fråga var ju "hur man kan testa detta".

Ja och "mitt" sätt att testa det kommer bli att jag skripta upp en körning och jämför resultat. Men tills dess för det brukar jag inte göra förrän det känns som koden inte kommer ändra sig så får det vara lite risky

Skrivet av Yoshman:

Givet signaturen och det faktum att denna funktion i praktiken jobbar med globala data gör det allt annat än lätt att skriva bra och framförallt blir det svårt att skriva väldigt korta/enkla unit-tester. Man kommer behöva sätta upp en del mocks för att göra någon vettig testning alls.

Håller med och samtidigt är det oftast i den här "skitkoden" som det är viktigaste. Metoder som fokuserarpå applikationens domän (hårdkodningen) brukar jag räkna som skitkod, kod som liksom är unik för applikationen och som använder annan (bra) kod. Därav de lite lustiga metodnamnet också men det är för att kunna känna igen och få viss ordning trots skitkod.
Givetvis skulle man kunna gräva ner sig i tester men även om man gör det är mycket involverat, bara en sådan sak som att det är språkagnostiskt/språkoberoende krånglar till det ordentligt för tester.

Skrivet av Yoshman:

Du kan alltid testa på Linux-kärnan. Den passerade 40 miljoner rader kod för en tid sedan.

Tack, bra tips

Permalänk
Datavetare
Skrivet av klk:

Ja och "mitt" sätt att testa det kommer bli att jag skripta upp en körning och jämför resultat. Men tills dess för det brukar jag inte göra förrän det känns som koden inte kommer ändra sig så får det vara lite risky

Använder du inte debugger??? För är långt enklare, snabbare och effektivare att göra det med unit-tester som är en enda binär skriven i samma språk/miljö som det man debuggar. Inte något som körs av ett externt skript.

Har testat rätt mycket precis på det sättet du beskriver. Givet det du skrev om "många rader C-kod" så var det rätt mycket så två tidiga C-projekt testade där ena var ~200k rader (skrivet på ca 1 år) och det andra ca ~300k rader (långt viktigare produkt och långt mer komplicerad, tog flera år innan det var 300k rader).

(Så att C-kod blir många rader är i sig inget mått på hög kvalité eller bra metoder. Det blir tyvärr rätt snabbt rätt mycket kod, inte minst när man gör services som hanterar nätverk, loggning, kryptering och signering...)

Att den koden testade på det sättet var lite en effekt av att den utvecklades för inbyggda-system där det krävdes en del krångel för att debugga "on-board". Att primärt skripta tester kändes lite som "det är nog lättast, framförallt när det finns bra TCP/IP/shell access till systemen".

Men var aldrig nöjd med det så ett sidoprojekt blev att skriva en simulator / OS-shim för hela miljön där alla produkterna kunde köras direkt på Linux / Windows. Då blev det rätt snabbt långt enklare att köra "vanliga" unit-tester.

Skrivet av klk:

Håller med och samtidigt är det oftast i den här "skitkoden" som det är viktigaste. Metoder som fokuserarpå applikationens domän (hårdkodningen) brukar jag räkna som skitkod, kod som liksom är unik för applikationen och som använder annan (bra) kod. Därav de lite lustiga metodnamnet också men det är för att kunna känna igen och få viss ordning trots skitkod.
Givetvis skulle man kunna gräva ner sig i tester men även om man gör det är mycket involverat, bara en sådan sak som att det är språkagnostiskt/språkoberoende krånglar till det ordentligt för tester.

Här håller jag inte med alls.

De interna bitarna ska också ha en välpolerat API och små enkla funktioner. Fördelen här är att det just är interna APIer, så man kan ju i långt större utsträckning försöka nå perfektion då man kan ändra APIer utan att kunder påverkas. När inte Hyrums Lag kommer och biter en i arslet!

Skrivet av klk:

Tack, bra tips

Efter att snabbt laddad ner senaste Linux-kernel och kört lite ripgrep: har för mig att du sa att du föredrar Windows.
Om så är fallet, är det ens meningsfull att blanda in flera CPU-kärnor?

På samma dator tog det ~5 gånger längre att packa upp Linux-source:en på Windows jämfört med Linux.
Att köra samma ripgrep fråga mot alla *.c filer gick "cache-cold" mer än 10 gånger snabbare på Linux, Windows behöver verkligen byta ut saker i sin filhantering för hanteringen av ett stort antal små filer är horribelt ineffektiv (har man få stora filer är Windows lika snabbt).

MacOS verkar ligga betydligt närmare Linux än Windows här, så är Windows som behöver mer jobb.

Så vill man få upp farten på filoperationer är det i nuläget långt mer effektivt att byta OS än att sätta sig och skriva nya program...

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Skrivet av klk:

Hur skulle du skriva test för följande kod?

/** --------------------------------------------------------------------------- * @brief Updates the pattern list for files in the cache using regex patterns and multithreading. * * This method processes a list of regex patterns and applies them to the files stored in the cache. * It generates a list of lines in each file where the patterns are found and stores the results * in the "file-linelist" cache table. The method uses multithreading to process files in parallel. * * @param vectorRegexPatterns A vector of pairs containing regex patterns and their names. * The vector must not be empty. * @param argumentsList Arguments for pattern processing (e.g., segment specification, max lines) * @param iThreadCount Number of threads to use (0 = auto-detect) * @return A pair containing: * - `bool`: `true` if the operation was successful, `false` otherwise. * - `std::string`: An empty string on success, or an error message on failure. * * @pre The `vectorRegexPatterns` must not be empty. * @post The "file-linelist" cache table is updated with the lines where the patterns are found. * * @note COMMAND_ListLinesWithPattern must be thread-safe. */ std::pair<bool, std::string> CDocument::FILE_UpdatePatternList(const std::vector<std::pair<boost::regex, std::string>>& vectorRegexPatterns, const gd::argument::shared::arguments& argumentsList, int iThreadCount) { assert(vectorRegexPatterns.empty() == false); // Ensure the regex pattern list is not empty using namespace gd::table; auto* ptableFile = CACHE_Get("file"); // Retrieve the "file" cache table auto* ptableLineList = CACHE_Get("file-linelist", true); // Ensure the "file-linelist" table is in cache assert(ptableFile != nullptr); assert(ptableLineList != nullptr); std::string_view stringSegment; if( argumentsList.exists("segment") == true ) { stringSegment = argumentsList["segment"].as_string_view(); } // Get the segment (code, comment, string) to search in uint64_t uMax = argumentsList["max"].as_uint64(); // Get the maximum number of lines to be printed auto uFileCount = ptableFile->get_row_count(); // Total number of files to process // ## Thread synchronization variables std::atomic<uint64_t> uAtomicFileIndex(0); // Current file being processed std::atomic<uint64_t> uAtomicProcessedCount(0); // Count of processed files std::atomic<uint64_t> uAtomicTotalLines(0); // Total lines found across all threads std::mutex mutexProgress; // Mutex to protect progress updates std::mutex mutexLineList; // Mutex to protect ptableLineList access std::vector<std::string> vectorErrors; // Collect errors from all threads std::mutex mutexErrors; // Mutex to protect access to vectorErrors // ## Worker function to process files in parallel ......................... auto process_ = [&](int iThreadId) -> void { // Create thread-local table for collecting results detail::columns* pcolumnsThread = new detail::columns{}; ptableLineList->to_columns( *pcolumnsThread ); std::unique_ptr<table> ptableLineListLocal = std::make_unique<table>(pcolumnsThread, 10, ptableLineList->get_flags(), 10); // Create local table with 10 rows pre-allocated while( true ) { uint64_t uRowIndex = uAtomicFileIndex.fetch_add(1); // get thread safe current index and increment it if(uRowIndex >= uFileCount) { break; } try { // STEP 1: Get file info (ptableFile is read-only so no mutex needed) auto stringFolder = ptableFile->cell_get_variant_view(uRowIndex, "folder").as_string(); auto stringFilename = ptableFile->cell_get_variant_view(uRowIndex, "filename").as_string(); // STEP 2: Build full file path gd::file::path pathFile(stringFolder); pathFile += stringFilename; std::string stringFile = pathFile.string(); auto uKey = ptableFile->cell_get_variant_view(uRowIndex, "key").as_uint64(); // STEP 3: Find lines with regex patterns gd::argument::shared::arguments arguments_({{"source", stringFile}, {"file-key", uKey}}); if( stringSegment.empty() == false ) arguments_.set("segment", stringSegment.data()); // Set the segment (code, comment, string) to search in auto result_ = COMMAND_ListLinesWithPattern(arguments_, vectorRegexPatterns, ptableLineListLocal.get()); // Find lines with regex patterns and update the local table if(result_.first == false) { std::lock_guard<std::mutex> lockErrors(mutexErrors); vectorErrors.push_back("File: " + stringFile + " - " + result_.second); uint64_t uProcessed = uAtomicProcessedCount.fetch_add(1) + 1; // Update progress even on failure if(uProcessed % 10 == 0) { std::lock_guard<std::mutex> lockProgress(mutexProgress); uint64_t uPercent = (uProcessed * 100) / uFileCount; MESSAGE_Progress("", {{"percent", uPercent}, {"label", "Find in files"}, {"sticky", true}}); } continue; // Skip to next file on error } // STEP 4: Append results to main table (FAST operation - mutex needed for thread safety) { std::lock_guard<std::mutex> lockLineList(mutexLineList); ptableLineList->append(ptableLineListLocal.get()); // Append the results from the local table to the main table // Update total line count and check if we've exceeded the maximum uint64_t uCurrentLines = uAtomicTotalLines.fetch_add(ptableLineListLocal->get_row_count()) + ptableLineListLocal->get_row_count(); if( uCurrentLines > uMax ) { uAtomicFileIndex.store(uFileCount); // Signal other threads to stop by setting file index to max } } ptableLineListLocal->row_clear(); // Clear local table rows for next iteration uint64_t uProcessed = uAtomicProcessedCount.fetch_add(1) + 1; // Update progress (thread-safe) if(uProcessed % 10 == 0) // Show progress every 10 files { std::lock_guard<std::mutex> lockProgress(mutexProgress); uint64_t uPercent = (uProcessed * 100) / uFileCount; MESSAGE_Progress("", {{"percent", uPercent}, {"label", "Find in files"}, {"sticky", true}}); } } catch(const std::exception& exception_) { std::lock_guard<std::mutex> lockErrors(mutexErrors); vectorErrors.push_back(std::string("Thread ") + std::to_string(iThreadId) + " error: " + exception_.what()); } } }; // ## Prepare and run threads .............................................. if( iThreadCount <= 0 ) { iThreadCount = std::thread::hardware_concurrency(); } // Use hardware concurrency if no thread count is specified if(iThreadCount <= 0) { iThreadCount = 1; } // Fallback to single thread if hardware_concurrency returns 0 if( iThreadCount > 8 ) { iThreadCount = 8; } // Limit to 8 threads for performance and resource management if( ptableFile->size() < iThreadCount ) { iThreadCount = (int)ptableFile->size(); } // Limit threads to number of files // Create and launch worker threads std::vector<std::thread> vectorPatternThread; vectorPatternThread.reserve(iThreadCount); for(int i = 0; i < iThreadCount; ++i) { vectorPatternThread.emplace_back(process_, i); } // Wait for all threads to complete for(auto& threadWorker : vectorPatternThread) { threadWorker.join(); } MESSAGE_Progress("", {{"clear", true}}); // Clear progress message // ### Handle any collected errors if(!vectorErrors.empty()) { for(const auto& stringError : vectorErrors) { ERROR_Add(stringError); } } return {true, ""}; }

Dold text

Om vi backar till "hur skulle du test detta" så är svaret att det skulle vi inte.

Efter att jag började skriva enhetstester så började jag skriva kod annorlunda. Det faktum att koden skall vara testbar gör att man inte skriver funktioner med med tresiffrigt antal rader och en cyklomatisk komplexitet på 34. Det går helt enkelt inte att testa (eller underhålla). Den är väl i princip så långt bort från Single Responsibility man kan komma (S:et i SOLID, du vet).

Bara det faktum att du använder ett lambda för att låta kompilatorn hålla reda på referenserna till ditt "funktions-globala" data ställer till det ur testbarhetssynpunkt. Hur skall man kunna testa det med enhetstester? Att bryta ut och sätta ett namn på lambdat vore ett första steg. (Du får skicka med en struct med referenser till allt data som [&] fångade.)

Om sedan steg 1, 2, 3, ... vore separata funktioner (med beskrivande namn) så närmar vi oss något som skulle vara testbart med enhetstester.

Att CDocument::FILE_UpdatePatternList inte går att testa med enhetstester är inte en brist hos enhetstestmetodiken...

Stavfel
Permalänk
Medlem
Skrivet av Yoshman:

Använder du inte debugger??? För är långt enklare, snabbare och effektivare att göra det med unit-tester som är en enda binär skriven i samma språk/miljö som det man debuggar. Inte något som körs av ett externt skript.

Inte externt skript utan brukar alltid koppla samman applikationer med LUA, supersmidigt, har bara possitiva erfarenheter av det
Givetvis debuggar jag också men brukar alltså fixa så att det går att automattesta

Skrivet av Yoshman:

Här håller jag inte med alls.

De interna bitarna ska också ha en välpolerat API och små enkla funktioner. Fördelen här är att det just är interna APIer, så man kan ju i långt större utsträckning försöka nå perfektion då man kan ändra APIer utan att kunder påverkas. När inte Hyrums Lag kommer och biter en i arslet!

Innan du har ett fint API har du alltid skitkod, det tar tid innan man vet vad något snyggt api skall ha och jag vet inte ens vad denna applikationen jag pysslar med nu skall göra till slut. Från början vart det ju bara en liten grej pojken lekte med men så kom vi på lite mer och så har det växt.
Försöker få till bra KANBAN hantering men det är en utmaning att köra konsol argument, lutar till att det bli ett litet gränssnitt.

Permalänk
Medlem
Skrivet av klk:

Men det är faktiskt idiotiskt, om man tror det går att skriva program i syfte att det skall bli intressant för andra så är man en idiot.

Fast detta är _INTE_ samma sak som:

Skrivet av klk:

Tänk att det finns idioter som skriver egna program.

De flesta programmen jag skriver till vardags är för att jag vill lära mig ett område eller lösa ett problem som framförallt stör mig. OM min kod blir intressant för någon annan så är det en trevlig bonus men det är sällan mitt mål.

Det är därför jag inte bryr mig om dina projekt utan kod här ska framförallt vara relaterat och avgränsat till diskussionen. Det är att du kommer med extraordinära påstående om din kod som är falska för att du inte verkar vara påläst som är störigt. Skryt på så länge du har något att komma med, typ som Jonathan Blow. Han är arrogant och skrytsam(passivt) men han har ju också producerat något respektabelt.

Skrivet av klk:

Förstår inte varifrån du fått att företag har bra kodkvalitet, var har du sett det?

Inget säger att hobbyprojekt inte kan ha bra kodkvalitet. Nu cherry-pickar du hobbyprojekt raddebugger, det finns ju Linux, cURL och en rad andra hobbyprojekt som lever i ett gränsland mellan hobby och företag. Om vi istället skulle blicka på den stora massan av hobbyprojekt som aldrig kommer någonstans som t ex skapades för att lösa det där problemet du störde dig på tills du läste manualen en andra gång och insåg att funktionaliteten redan existerade osv som bara ligger och skräpar på Github (personligen har jag nog 40 sådana projekt och i min projekt katalog så är där nog 40 till) så tror jag inte att dessa håller högre kodkvalitet en företagskod.

Jag tror en stor skillnad är när du har betalande kunder och kan hållas juridiskt ansvarig för din kod.

På företag som jag jobbat på så har det var 100% coverage i unit tester, functional tester positiva och negativa, QA-avdelningar och 8 timmar med integrationstestning innan din patch merge:ades, externa företag som granskar och testar produkten. Personligen har jag inte den mängden resurser avsatt till testning i mina hobbyprojekt och jag misstänker att du inte har det i heller.

Jag har även sett ett sådan maskineri hitta obskyra buggar innan det nått kunden så det fungerar bevisligen.

Permalänk
Medlem
Skrivet av Yoshman:

Efter att snabbt laddad ner senaste Linux-kernel och kört lite ripgrep: har för mig att du sa att du föredrar Windows.
Om så är fallet, är det ens meningsfull att blanda in flera CPU-kärnor?

På samma dator tog det ~5 gånger längre att packa upp Linux-source:en på Windows jämfört med Linux.
Att köra samma ripgrep fråga mot alla *.c filer gick "cache-cold" mer än 10 gånger snabbare på Linux, Windows behöver verkligen byta ut saker i sin filhantering för hanteringen av ett stort antal små filer är horribelt ineffektiv (har man få stora filer är Windows lika snabbt).

MacOS verkar ligga betydligt närmare Linux än Windows här, så är Windows som behöver mer jobb.

Så vill man få upp farten på filoperationer är det i nuläget långt mer effektivt att byta OS än att sätta sig och skriva nya program...

Har precis testat i windows och nu fick den jobba lite, kan pröva på linux (wsl och mac) sedan

Tog jag rubbet så vart det så här

37,348 miljoner rader

Får inte samma resultat som ripgrep men det beror nog på att min bara räknar filer den känner igen eller om det är vanliga utf8 eller ascii filer, får börja jämföra snart

Permalänk
Medlem
Skrivet av orp:

Det är därför jag inte bryr mig om dina projekt utan kod här ska framförallt vara relaterat och avgränsat till diskussionen. Det är att du kommer med extraordinära påstående om din kod som är falska för att du inte verkar vara påläst som är störigt. Skryt på så länge du har något att komma med, typ som Jonathan Blow. Han är arrogant och skrytsam(passivt) men han har ju också producerat något respektabelt.

Visst är det jobbigt när någon skryter men det är också bra om man vill få ärliga åsikter.

Samtidigt så finns en "utveckling" inom programmering så är så otroligt trist för elakare personer i en yrkeskår är nog svår att hitta och det förstår jag inte hur det kunna bli så. Så här var det inte alls förr, när jag började var det typ endast "töntar" som programmerare men alla tyckte om det och det var bara roligt om någon kom med nya ideer. Strax efter 2005 ungefär så vände det och nu räcker det med att säga att man använder kodstilen Hungarian Notaion så är risken stor att man åker ut med huvudet före.

Ny utvecklare idag med lite sämre självförtroende blir direkt mosade bland alla som "vet" och det kommer ena dumheten efter den andra.

Permalänk
Medlem
Skrivet av klk:

Visst är det jobbigt när någon skryter men det är också bra om man vill få ärliga åsikter.

Samtidigt så finns en "utveckling" inom programmering så är så otroligt trist för elakare personer i en yrkeskår är nog svår att hitta och det förstår jag inte hur det kunna bli så. Så här var det inte alls förr, när jag började var det typ endast "töntar" som programmerare men alla tyckte om det och det var bara roligt om någon kom med nya ideer. Strax efter 2005 ungefär så vände det och nu räcker det med att säga att man använder kodstilen Hungarian Notaion så är risken stor att man åker ut med huvudet före.

Ny utvecklare idag med lite sämre självförtroende blir direkt mosade bland alla som "vet" och det kommer ena dumheten efter den andra.

Där har du en poäng. Förr var det färre språk i omlopp och antalet "arbetsmetoder" hade inte dokumenterats och drivits på av "konsulter". Det var väl på sin höjd som så att en kunde FORTRAN, en annan kunde C och någon kunde både C och FORTRAN. Någon yngre räckte upp handen och sa att han kunde Pascal, varpå de andra tre ropade att ingen använder Pascal i verkligheten.

Med tiden har allt fler språk dykt upp som alla kämpar om en plats på scenen och ovanpå detta så finns det numera många olika filosofier om hur man skriver hållbar kod. Därmed har armbågarna vässats, vilket vi ser i smått och stort (t.ex. Linux-kärnan).

En annan aspekt är att programmeringskonsten nu har mognat och nya generationer kommer till. De gamla uvarna har blivit, ja äldre, och vi vet ju att äldre (jag) kan ha lite svårt att ta till sig det nya. Jag pratade nyligen med en 80-åring och förklarade att vart 20'e år så sker det ett generationsskifte där nya sätt att tänka etableras vilket gör det svårt att bryta igenom den utveckling som skett. Jag skulle säga att AI är ett sådant här skifte som gör det svårt att ta in hur det faktiskt fungerar (om någon ens egentligen vet det?). Därför känns det tryggt och säkert att fortsätta skriva i det jag kan, C, bash (ksh) eller att nosa lite på Python om det är något speciell modul jag är ute efter.

Permalänk
Medlem
Skrivet av klk:

Visst är det jobbigt när någon skryter men det är också bra om man vill få ärliga åsikter.

Nej, det är som sagt inte jobbigt när någon skryter och visar upp något imponerande. Det är jobbigt när någon skryter utan att visa upp något, då ser det mest verklighetsfrånkopplat och korkat ut. Det ser ut som Idol-uttagningarna som folk skrattar åt när det är folk som hävdar att dom är nästa Pavarotti men i själva fallet är tondöva och står och joddlar som en 14-åring i målbrottet på scen.

Skrivet av klk:

Samtidigt så finns en "utveckling" inom programmering så är så otroligt trist för elakare personer i en yrkeskår är nog svår att hitta och det förstår jag inte hur det kunna bli så.

Jag svarar hårt som ett resultat av att du slänger ur dig felaktiga och absurda kommentarer och vägrar acceptera motbevisning ihop med att du har en historia av att uttala dig nedlåtande om vissa kategorier av utvecklare samtidigt som du inte gett intrycket av att vara en särskilt bra utvecklare själv.

Jag accepterar alla nivåer av utvecklare men jag tycka aldrig att det är OK och sitta och kasta skit på andra, då förtjänar man skit tillbaka enl. mig.

Skrivet av klk:

Så här var det inte alls förr, när jag började var det typ endast "töntar" som programmerare men alla tyckte om det och det var bara roligt om någon kom med nya ideer. Strax efter 2005 ungefär så vände det och nu räcker det med att säga att man använder kodstilen Hungarian Notaion så är risken stor att man åker ut med huvudet före.

Jag tror ingen har så starka känslor kring hungarian notion men att säga saker som att "unit test är värdelöst" eller att "pythonutvecklare inte är riktiga programmerare" osv då förtjänar man att åka ut med huvudet före.

Hade du sagt "jag gillar inte unit test och vi har inte upplevt bristfällig kvalitet utan unit test" och "jag gillar inte python" så hade jag inte haft några problem med det.

Skrivet av klk:

Ny utvecklare idag med lite sämre självförtroende blir direkt mosade bland alla som "vet" och det kommer ena dumheten efter den andra.

Nej, inte så länge dom inte beter sig som att dom är bäst i världen och snackar skit om sina kollegor.

Permalänk
Medlem
Skrivet av orp:

Jag tror ingen har så starka känslor kring hungarian notion men att säga saker som att "unit test är värdelöst" eller att "pythonutvecklare inte är riktiga programmerare" osv då förtjänar man att åka ut med huvudet före..

Men python är inte "riktig" imperativ utveckling, det är deklarativ utveckling även om de får ta till imperativa kodavsnitt. Och unit test har stora konsekvenser på koden, för en som lärt sig utveckla (imperativ kod) så medför bara unit test en massa problem. Det kostar mycket mer än vad det smakar och det är inte ens konstigt. Det enda är att tröskeln till att förstå varför är högre än om utvecklare gått en veckas kurs i html.

Om jag läser instruktioner hur man använder hammare och spik, kanske lär mig en del verktyg till. Köper virke och bygger ett hus. Det råkar se ut som en hydda men det är i all fall tak över huvudet. Kan jag då kalla mig snickare?

Gör ett försök att förklara
Tidigare i tråden postade jag en del kod för en metod som heter FILE_UpdatePatternList och nämnde senare att det är skitkod. Orsaken till att jag kallar det för skitkod beror på att det ÄR skitkod.
Skitkod är svårt att undvika helt och hållet men desto mer man lär sig desto mindre skitkod blir det.

Så varför är det skitkod?

  • Koden hanterar användardomänen (användardomän är ett områden utvecklare måste läsa på för att klara av att jobba i koden). All kod som hanterar användardomän är skitkod.

  • Metoden FILE_UpdatePatternList gör flera saker, en metod skall inte göra flera saker, den skall göra EN sak.

  • Metoden har massor av variabler trots att ansträngningarna att minimera antalet så är det ändå många

  • Metoden är tekniskt svår och mycket svår att debugga.

En riktig utvecklare förstår hur viktigt det är att minimera skitkod, gör man inte det går det inte att utveckla applikationer för att istället för att skapa funktionalitet kommer förstöra. Att en del ändå lyckas beror på att man följer ramverk. Programmeraren skriver inte egen funktionalitet utan använder komponenter och då kan man komma längre men inte hur långt som helst. Hjärnan klarar inte minnas hur mycket som helst.

Mängden kod för de som kan programmera spelar ingen roll, om det är 10 000 rader kod eller 20 miljoner, det är skit samma kodmässigt. Kan man inte programmera spelar mängden stor roll eftersom kod ofta skrivs efter någons huvud. Vad som finns i en programmerares huvud finns inte automatiskt i andra programmerares huvud. Enklare domäner så fungerar det ändå eftersom variabelnamn och andra namn kan tillhöra allmänbildning. Svårare domäner och koden är omöjlig att förstå. Endast den som skrivit koden förstår vad den gör.

Separera systemdomän från användardomän är viktigt. (använder de namn som Casey Maratori beskrev så bra). Det finns en bok som heter "clean code" skriven av Robert C Martin. Sämsta bok som skrivits och förstört massor eftersom den beskriver att bra kod är att skriva kod för användardomän. Att kod är som att läsa en bok.
Att den blev så populär tror jag beror på att många kunde äntligen göra något programmeringsmässigt. Så de trodde "nu är jag programmerare". Försöker då en "riktig" programmerare förklara att man inte gör som de lärt sig så förstår de inte alls.

32 variabler in metoden FILE_UpdatePatternList
Metoden FILE_UpdatePatternList har alltså 32 stycken variabler, vansinne men det fungerar med hungarian notation. Det här är en av de hungarian notation största styrkor, det är så mycket enklare att förstå skitkod. Om programmeraren inte har något system för benämning av variabler kommer programmeraren aldrig att klara av att skriva den typen av kod (även om det är skitkod) och det kommer definitivt inte vara möjligt att läsa koden. Utan tekniker för hur kod hanteras kommer utvecklaren förmodligen inte klara att skriva speciellt avancerad kod alls. Det har alltså inget med skicklighet att göra utan det är en teknik.
Style guide och annat hur kod skrivs anpassas helt efter att klara av att hantera skitkod.

Here are the variables extracted from this method: ## Function Parameters: - `vectorPattern` (const std::vector<std::string>&) - List of search patterns - `argumentsList` (const gd::argument::shared::arguments&) - Command line arguments - `iThreadCount` (int) - Number of threads to use ## Local Variables: - `patternsFind` (gd::parse::patterns) - Sorted pattern collection - `ptableFile` (auto*) - Pointer to file cache table - `ptableLineList` (auto*) - Pointer to line list cache table - `stringSegment` (std::string_view) - Code segment to search in (code, comment, string) - `uMax` (uint64_t) - Maximum number of lines to process - `uFileCount` (auto) - Total number of files to process ## Thread Synchronization Variables: - `uAtomicFileIndex` (std::atomic<uint64_t>) - Current file being processed - `uAtomicProcessedCount` (std::atomic<uint64_t>) - Count of processed files - `uAtomicTotalLines` (std::atomic<uint64_t>) - Total lines found across threads - `mutexProgress` (std::mutex) - Protects progress updates - `mutexLineList` (std::mutex) - Protects ptableLineList access - `vectorError` (std::vector<std::string>) - Collects errors from threads - `mutexErrors` (std::mutex) - Protects access to vectorError - `pcolumnsThread` (detail::columns*) - Column structure for line list table ## Lambda Function Variables (process_): - `iThreadId` (int) - Thread identifier - `ptableLineListLocal` (std::unique_ptr<table>) - Thread-local results table - `uRowIndex` (uint64_t) - Current file row index - `stringFolder` (auto) - File folder path - `stringFilename` (auto) - File name - `pathFile` (gd::file::path) - Full file path object - `stringFile` (std::string) - Full file path string - `uKey` (auto) - File key identifier - `arguments_` (gd::argument::shared::arguments) - Arguments for pattern matching command - `result_` (auto) - Result from pattern matching operation - `uProcessed` (uint64_t) - Local processed file count - `uPercent` (uint64_t) - Progress percentage - `exception_` (const std::exception&) - Exception object ## Thread Management Variables: - `vectorPatternThread` (std::vector<std::thread>) - Collection of worker threads - `threadWorker` (auto&) - Reference to worker thread in loop

Dold text

Hur jag vet att exempelvis rust eller andra "förlåtande" språk inte kommer användas till större svårare projekt
Vet man om ovanstående så är det ganska lätt och se hur långt ett projekt kommer. Det beror en del på vilken typ av domän koden hanterar. Är det domäner kända för utvecklare kommer de längre, är det ovanliga så kommer de inte speciellt långt.
Att utveckla en editor, spelmotor eller annat kan komma ganska långt även om det är tekniskt men det beror på att användardomänen också är känd för utvecklare.
Är det annat som vetenskapliga domäner eller liknande, då bli det genast mer problem.

Eftersom jag granskat en del rust projekt så, i princip samtliga rust projekt jag kollat uppträder för mycket "skitkod" och det är enligt mig orsaken till att de inte kommer så långt. Ett allvarligt designfel de har i rust är att språket saknar överlagring och det gör att att de har mycket svårare att skriva kod i mönster. Nästan alla "kända" rust projekt har en eldsjäl och de kan nå närmare 100 000 rader och då är det vad jag sett nästan alltid domäner välkända för utvecklare. Har inte sett rustprojekt med något mer udda domän som är större men tar gärna emot tips på sådant. Att det saknas projekt i domäner okända för utvecklare tror inte jag är en slump.

Permalänk
Datavetare
Skrivet av klk:

Visst är det jobbigt när någon skryter men det är också bra om man vill få ärliga åsikter.

Samtidigt så finns en "utveckling" inom programmering så är så otroligt trist för elakare personer i en yrkeskår är nog svår att hitta och det förstår jag inte hur det kunna bli så. Så här var det inte alls förr, när jag började var det typ endast "töntar" som programmerare men alla tyckte om det och det var bara roligt om någon kom med nya ideer. Strax efter 2005 ungefär så vände det och nu räcker det med att säga att man använder kodstilen Hungarian Notaion så är risken stor att man åker ut med huvudet före.

Ny utvecklare idag med lite sämre självförtroende blir direkt mosade bland alla som "vet" och det kommer ena dumheten efter den andra.

Om man använde Hungarian Notaion 2005 så kanske man bara inte riktigt hämtat sig från att det blev ett nytt årtusende. Om man fortfarande använder det 2025 kanske man borde fundera på pension

Edit: lite mer seröst. Det fanns helt klart en poäng med HN på 80 och tidigt 90-tal p.g.a. bristande mognadsgrad i språkdesign och framförallt i IDE/textredigerare för kod.

Men även Microsoft säger detta idag

Citat:

Microsoft’s Official Guidelines

From Microsoft’s .NET Framework Design Guidelines (and later Visual Studio documentation):
• Discouraged for new code:
“Do not use Hungarian notation or any other type identification in identifiers.”
Instead, rely on descriptive names and type information from the compiler/IDE.
• Reasoning:
• Type encodings are redundant in strongly typed languages like C#.
HN reduces readability (strName vs name).
Refactoring breaks naming consistency if prefixes aren’t updated.
• Exceptions allowed:
Microsoft acknowledges semantic prefixes (closer to Apps Hungarian) can be useful. For example:
• ui for user input vs. db for database value.
• rawPassword vs. hashedPassword.
These prefixes clarify intent/meaning, not type.

Självklart ändras yrket. Sättet kod utvecklas var innan millenieskiftet väldigt omoget och jämfört med många andra ingenjörsdiscipliner är det fortfarande rätt omoget.

Skulle säga att många unga från skolan är idag bättre förberedda än vad vi som tog examen på 90-talet var. Framförallt gäller det de främst lärt sig yrket från skolan, inte som hobby.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av Yoshman:

Om man använde Hungarian Notaion 2005 så kanske man bara inte riktigt hämtat sig från att det blev ett nytt årtusende. Om man fortfarande använder det 2025 kanske man borde fundera på pension

Vet du någon annan kodstil för att hantera kod
För ändringen är "skriv kod som du själv vill". Vad jag vet är det endast hungarian notation som finns och vars syfte är att hantera svår kod. Det kan vara mycket kod, avancerad kod, svår domän eller liknande. Hjärnan behöver inte arbeta lika mycket och kan därför lägga energi på annat.

Det nya är deklarativ programmering, istället för att skriva kod som programmerare gör så skriv en bok. Inget som ersätter utan det är något helt annat eftersom imperativ kod jämfört med deklarativ kod ofta är varandras motsatser.

Permalänk
Medlem
Skrivet av klk:

Men python är inte "riktig" imperativ utveckling, det är deklarativ utveckling även om de får ta till imperativa kodavsnitt.

Det är nog tredje gången i denna tråden som jag måste förklara för dig att Python är ett riktigt imperativt språk lika mycket som C++.

Skrivet av klk:

Och unit test har stora konsekvenser på koden, för en som lärt sig utveckla (imperativ kod) så medför bara unit test en massa problem.

Imperativt eller deklarativt unit tester är varken lättare eller svårare baserat på paradigm utan beror mer på om din kod är väl designad.

Skrivet av klk:

Det kostar mycket mer än vad det smakar och det är inte ens konstigt. Det enda är att tröskeln till att förstå varför är högre än om utvecklare gått en veckas kurs i html.

Nu har jag mer än en veckas kurs i HTML och tycker att det är tydligt att du har så pass dålig koll på unit testning att du troligen inte kan avgöra hur mycket det kostar eller smakar.

Skrivet av klk:

Om jag läser instruktioner hur man använder hammare och spik, kanske lär mig en del verktyg till. Köper virke och bygger ett hus. Det råkar se ut som en hydda men det är i all fall tak över huvudet. Kan jag då kalla mig snickare?

Du har ju ingen till lite erfarenhet av unit testning trots det uttalar du dig om unit test som om du har någon auktoritet i ämnet... dvs du gör samma missar som du predikar om.

Skrivet av klk:

Tidigare i tråden postade jag en del kod för en metod som heter FILE_UpdatePatternList och nämnde senare att det är skitkod.

Måste jag påminna dig om detta var vad du skrev innan @Yoshman gav dig en lista med förbättringsförslag?

Skrivet av klk:

Hur skulle du skriva test för följande kod (alltså mer ett resonemang, skriv ingen kod för den är svår att skriva test för), satt precis och gjorde den så det kanske är någon bugg

Detta handlade om att du inte fattade frågan om hur du skulle testa min exempelkod på 13 rader med din stil av testning. Istället började kommentera om helt irrelevanta saker. Lite som att skulle kalla dig själv en snickare och när någon hyr in dig för att byta en murken bit ytterpanel i fasaden så börjar du gnäll om att det är fel färg på fasaden och pekar på din egna murkna fasad och säger till ägaren kan du byta min fasad istället?

Skrivet av klk:

Orsaken till att jag kallar det för skitkod beror på att det ÄR skitkod. ...

Sorry men jag bryr mig inte riktigt om ditt yrande om vad du anser är skitkod. Jag bryr mig inte heller om vad Casey Maratori har att säga, clean code, kodrader eller hungarian notion. Det vi pratade var om testning och hur du testar, så hur testar du?

Skrivet av klk:

Hur jag vet att exempelvis rust eller andra "förlåtande" språk inte kommer användas till större svårare projekt
Vet man om ovanstående så är det ganska lätt och se hur långt ett projekt kommer.

Det används ju redan i "större svårare projekt" så än en gång säger du saker som redan är motbevisade.

Skrivet av klk:

Eftersom jag granskat en del rust projekt så, i princip samtliga rust projekt jag kollat uppträder för mycket "skitkod" och det är enligt mig orsaken till att de inte kommer så långt.

Ge ett exempel

Skrivet av klk:

Ett allvarligt designfel de har i rust är att språket saknar överlagring och det gör att att de har mycket svårare att skriva kod i mönster.

Fast det går att åstadkomma liknande överlagring om man hade tagit en veckas kurs i Rust istället för HTML.

Permalänk
Skrivet av klk:

Vet du någon annan kodstil för att hantera kod
För ändringen är "skriv kod som du själv vill". Vad jag vet är det endast hungarian notation som finns och vars syfte är att hantera svår kod. Det kan vara mycket kod, avancerad kod, svår domän eller liknande. Hjärnan behöver inte arbeta lika mycket och kan därför lägga energi på annat.

Det argumentet bet inte alls på dig när vi pratade om smart pointers. Smart pointers var stödhjul och krycka för folk som inte kunde bättre. Att man kunde spendera sina hjärncykler on the real problem var inte viktigt. Riktiga programmerare klarade sig bättre utan smart pointers för då fick man smaka på alla underbara överraskningar som manuell minneshantering bjöd på och man blev en bättre programmerare.

I mina ögon är HN bara extra brus som gör koden svårare att läsa. Om man inte klarar att förstå vad koden gör utan HN skriver man inte för komplicerade funktioner då? Hur kommer de sig att HN är ett hjälpmedel som gör att hjärnan kan jobba med det viktiga när inte smart pointers är det?

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Det argumentet bet inte alls på dig när vi pratade om smart pointers. Smart pointers var stödhjul och krycka för folk som inte kunde bättre. Att man kunde spendera sina hjärncykler on the real problem var inte viktigt. Riktiga programmerare klarade sig bättre utan smart pointers för då fick man smaka på alla underbara överraskningar som manuell minneshantering bjöd på och man blev en bättre programmerare.

Pekare (kontroll av minne) är viktigt för att skriva smidig återanvändbar kod.

På utsidan ser det normalt ut, internt händer det en hel del
Normalt när programmerare gör sådant här skapar den en struct och lagrar det i vector.

exempel:

auto ptableLineList = std::make_unique<gd::table::dto::table>(gd::table::dto::table(uTableStyle, { {"uint64", 0, "key"}, {"uint64", 0, "file-key"}, {"rstring", 0, "filename"}, {"rstring", 0, "line"}, {"uint64", 0, "row"}, {"uint64", 0, "column"}, {"string", 32, "pattern"}, {"string", 10, "segment"} }, gd::table::tag_prepare{}) ... detail::columns* pcolumnsThread = new detail::columns{}; ptableLineList->to_columns( *pcolumnsThread ); ... std::unique_ptr<table> ptableLineListLocal = std::make_unique<table>(pcolumnsThread, 10, ptableLineList->get_flags(), 10); // Create local table with 10 rows pre-allocated ... std::lock_guard<std::mutex> lockLineList(mutexLineList); ptableLineList->append(ptableLineListLocal.get()); // Append the results from the local table to the main table