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

Permalänk
Medlem
Skrivet av orp:

Då förändras inte koden eller så är dina tester dåligt skrivna.

Ursäkta skrytet men det är ganska sällsynt att det är i min kod det är problem Det är inte så svårt att skriva bra kod men man kan inte lyssna på alla konstigheter folk hittat på.

Skrivet av orp:

Detta låter som lathet.

Ja och lata programmerare är duktiga, att hata att rätta buggar är en mycket bra egenskap för då anstränger man sig för att undvika buggarna. De kodare som skriver bäst kod är de som älskar att programmera men hatar att rätta kod.

Permalänk
Medlem
Skrivet av orp:

asserter kommer ju att terminera ditt program och företagen jag har jobbat för så är detta strikt förbjudet i produktion utan fel ska alltid försökas hanteras, enda undantaget har varit fel som om man misslyckas med allokering av minne men även här har jag sett fall när man gör en delvis teardown och lägger sig i en retry-loop tills man kan allokera igen.

Fråga: Använder du inte assert's?

Permalänk
Skrivet av klk:

Vill understryka att jag absolut inte är emot att testa kod. tvärtom så anser jag att det är så viktigt att kod skall testas att man behöver välja bättre teknik än vad unit-test är. unittester är för dåligt.

Utvecklare som sätter likhetstecken mellan "inga unit-tester" = "ingen kontrol" har inte prövat annat för att säkerställa koden.

Enligt mig skall kod designas utifrån att den skall skall vara säker, man väljer till och med lösningar för att säkra koden,

Skriver jag C++ kod så är den marinerad med assert eller för att ta javascript, där är det massor console.assert. Varenda programmeringsfel bör plockas genom att koden kontrollerar sig själv.

Har jag uppfattat det korrekt om jag drar slutsatsen att din bättre metod för att testa är att sprinkla koden med asserts? Hur kollar du då att den kan hantera alla fall korrekt? nullptr, randvärden, specialfall? asserts i koden kan ju bara reagera på det flöde som inkommande parametrar styr det till. Med unit-tester är det lätt att testa att de externt synliga funktionerna hanterar ett par typvärden och randvärden korrekt. Jag ser inte hur du får till det på ett enkelt sett med asserts.

Skrivet av klk:

De två stora problemen med unit-tester är att de fångar för lite fel och gör koden mycket mer trögjobbad och det i sin tur leder till sämre kvalitet.

Man kanske då undrar hur jag vet det här? Ganska enkelt att testa genom att se vilka som får slita med buggar i deras kod.

Varför gör det koden trögjobbad? Om du upplever det tror jag att du försöker testa fel saker med dina unit-tester.

Min erfarenhet är att en uppsättning med vältäckande unit-tester är till stor hjälp. Jag gör inte färre fel, men oftast när jag gör fel får jag ofta veta det redan när jag försöker kompilera (och de automatiserade testerna körs). Felet har typiskt gjorts i det senaste jag ändrade och jag har testfall som påvisar exakt vad som går fel med den ändringen jag försökte göra. Utan dessa tester hade felet upptäckts i ett senare skede utan att jag har kvar kontexten i huvudet. I mitt fall sliter jag mycket mer med buggarna i legacy som saknar unit-tester.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Har jag uppfattat det korrekt om jag drar slutsatsen att din bättre metod för att testa är att sprinkla koden med asserts?

Det är inte korrekt uppfattat. Nämnde assert för om en utvecklare säger att unit-tester är viktiga men inte använder assert så har vederbörande diskvalificerat sig själv från diskussionen :). assert är absolut inte något som ersätter releasebuggar men assert är fantastiskt för att få en smidig kod att jobba med. Utvecklare får omedelbar respons när de använder något felaktigt. assert premierar också bra tankesätt, att utvecklare lär sig tänka säkerhet medan de skriver funktionalitet.

Skrivet av Ingetledigtnamn:

Hur kollar du då att den kan hantera alla fall korrekt? nullptr, randvärden, specialfall?

Behöver mer kontext för att kunna svara på olika fall men just nu håller jag på att parallellisera kod. Koden som skall parallelliseras, där visste jag innan att den skulle köras parallellt. Eftersom jag visste det så är designen gjord så att delar i funktionalitet är anpassad för den uppgiften. Kan också slå av trådningen, köra det i en tråd.
Beskriver för att förklara att hela kodavsnittet är anpassad för att dels kunna testas, och efter en slutlig lösning.

Beroende på vad det är som görs behöver man enligt mig planera för säkerheten, ibland blir det inte bästa lösning sett till funktionalitet på grund av säker kod är viktigare.

Sett till tester tycker jag regresionstester (tror jag det kallas) är att föredra. Då kör du skarp kod direkt och normalt för mig är att jag slår på loggningen och den sprutar ut med olika format, exempelvis csv och då kan man snabbt få upp det i något excelark och granska där. Beror på hur viktigt det är.

Alla metoder som är beroende av något externt där det kan gå fel, där returneras alltid felinformation, inte värden. Värden returneras med referenser eller pekare till objekt som "fylls".

Samma mönster används för att returnera fel för att kunna bygga generell kod kring felhanteringen.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Varför gör det koden trögjobbad? Om du upplever det tror jag att du försöker testa fel saker med dina unit-tester.

Eftersom om du ändrar i kod som har tester skriva mot koden behöver du också skriva om testerna. Det kan till och med vara så illa så att förbättringar i befintlig kod undviks på grund av att utvecklare inte "orkar" skriva om tester (supervanligt)
Ofta är det vanligt att det smäller i tester utan att det är något fel. Finns mycket med unittester som gör att att koden blir seg som sirap att jobba med.

Permalänk
Medlem
Skrivet av klk:

Sett till tester tycker jag regresionstester (tror jag det kallas) är att föredra. Då kör du skarp kod direkt och normalt för mig är att jag slår på loggningen och den sprutar ut med olika format, exempelvis csv och då kan man snabbt få upp det i något excelark och granska där. Beror på hur viktigt det är.

Själv är jag av olika anledningar inte så förtjust i unit-tester, men en sak de är bra för är just regressionstestning.

Permalänk
Medlem
Skrivet av klk:

Ursäkta skrytet men det är ganska sällsynt att det är i min kod det är problem Det är inte så svårt att skriva bra kod men man kan inte lyssna på alla konstigheter folk hittat på.

Det är lätt att hävda att sin kod är felfri när den inte testas ordentligt. Jag har enbart observerat en person(djb) som har rätt till att skryta om detta och det är inte du.

Skrivet av klk:

Ja och lata programmerare är duktiga, att hata att rätta buggar är en mycket bra egenskap för då anstränger man sig för att undvika buggarna. De kodare som skriver bäst kod är de som älskar att programmera men hatar att rätta kod.

Håller inte med dig. Lata programmerare skriver inte kod. Logiskt sett så skriver dom iaf mindre kod och om man skriver mindre kod så utvecklas man inte i samma takt som andra utvecklare och borde därför vara mindre produktiva och effektiva.

Permalänk
Medlem
Skrivet av klk:

Fråga: Använder du inte assert's?

Nästintill aldrig. Jag använde det flitigt runt 2010 men sedan dess har jag inte jobbat för någon som tillåter det framförallt inte istället för testning. Jag använder asserts när programmet måste krascha och det är tillåtet att krascha programmet.

Personligen så gillar jag inte TDD och inte heller överdriven testning som att försöka uppnå 100% coverage. Jag tycker om att unit testa logik. Jag gillar det även för viss utveckling, t ex om jag ska utveckla en parser så är det ganska skönt att testa av allt eftersom man introducerar hantering av nya tokens, då är det lätt att kontrollera att tokeniseringen hanterar förväntade sekvenser.

Jag gillar även regressionstestning och som @Erik_T nämnde så är ju unit tester perfekta för detta.

Permalänk
Medlem
Skrivet av orp:

Nästintill aldrig. Jag använde det flitigt runt 2010 men sedan dess har jag inte jobbat för någon som tillåter det framförallt inte istället för testning. Jag använder asserts när programmet måste krascha och det är tillåtet att krascha programmet.

En undran: Varför är det ok att göra det ena men inte det andra och tänker då på att testa men skippa assert, men inte att använda assert fast testa. Borde det inte vara bättre att göra båda saker?

Och det är väl ingen som använder assert i release kod? då har man missat något i utbildningen

Jag anar att ni knappt använder debuggern, stämmer det?

Permalänk
Datavetare
Skrivet av klk:

Nej det vet du inte

Jo det vet jag därför det inte är svårare att reda ut än att mäta med och utan detta. För mig är det netto positivt.

Skrivet av klk:

Och vi har precis diskuterat ett mycket svårt problem som blir enkelt med smartare arkitektur. Att unit-testing är värdelöst har samma grund som att bygga kod kring fel domän.
Kod lever när det handlar om anävndardomänen för det är väldigt få förunnat som skriver kod kring något som aldrig ändrar sig. Att unittesta saker som ändrar sig innebär bara mer kod att skriva om med ett värdelöst sätt att hitta buggar på. Har heller aldrig mött någon som kan skriva bra tester, att skriva bra tester är svårare än att skriva produktionskod. I princip varenda annan teknik för att testa kod är bättre, enda gången unit tester är bra för att testa att kod fungerar är om man vill skydda koden, låsa "fast den"

Hmm... Du har uppenbarligen aldrig ens varit i närheten av säkerhetskritisk kod, t.ex. avionic system certifierade enligt DO-178C.

Där har du exempel på kod som efter den certifierats (är skitdyrt, kostar i storleksordningen 100 USD per rad kod) är helt fryst och kan ändå användas under årtionden.

Så finns definitivt fall där "kod aldrig ändrar sig" inom högst relevanta områden (finns något liknande för andra områden, men har själv bara jobbat med just DO-178C).

Skrivet av klk:

Angående att sådant här var så mycket lättare att diskutera förr jämfört med idag. Skulle man göra Win32 applikationer i C/C++ kände i princip alla till LPARAM and WPARAM och det var automatiskt ett naturligt sätt att tänka.
När man abstraherat bort underliggande teknik får utvecklare inte kontakt med sådant och känner därför inte till det.

Hur är WPARAM/LPARAM på något sätt "ett naturligt sätt att tänka?". De är implementationsdetalj i Win32 APIet man behöver bry sig om på det lägsta nivån men som i en vettig design man lägger under en mer lämplig abstraktion där PostMessage/GetMessage i praktiken bara är en kommunikationsmekanisk för att schemalägga specifika kodsektioner+associerad data att köras på en specifik tråd (normalfallet är att man vill schemalägga något på GUI-tråden).

Skrivet av klk:

Vill understryka att jag absolut inte är emot att testa kod. tvärtom så anser jag att det är så viktigt att kod skall testas att man behöver välja bättre teknik än vad unit-test är. unittester är för dåligt.

Det är dåligt om skill-level i att skriva bra unit-tester är så låg att det blir ett sänke. Finns absolut en lång rad sätt att skriva dåliga unit-tester som stjälper mer än hjälper. Men har man når "tillräckligt" hög skill-level i att skriva unit-tester har jag lite svårt att se exakt vad man kan ersätta det värde dess ger med något annat.

Skrivet av klk:

Skriver jag C++ kod så är den marinerad med assert eller för att ta javascript, där är det massor console.assert. Varenda programmeringsfel bör plockas genom att koden kontrollerar sig själv.

Använder också väldigt ofta assert. De har dock ett annat syfte jämfört med unit-tester och framförallt kan inte asserts testa saker som kräver ett större specifikt kontext för att trigga specifika fall.

Asserts huvudpoäng är dokumentation då de är ett bra sätt att uttrycka antaganden om t.ex. möjliga värden för argument, att man aldrig hamnar i ett icke-förväntat tillstånd under en beräkning etc.

Men normalfallet är väl ändå att asserts inte är med i release-byggen? Det tillåter att man ibland kan ha hyfsat komplicerade/dyra beräkningar för säkerställa att pre/post tillstånd är inom förväntade värden.

Fast här ser man också fördelen i att använda "memory safe languages", de har en lång rad implicita tester just kring att man inte hamnat i ett felaktigt tillstånd. I C och C++ behöver man lägga in allt det explicit i sin egen kod och i 3:e-parts kod har man kanske inte ens möjligheten om man saknar källkoden.

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 klk:

En undran: Varför är det ok att göra det ena men inte det andra och tänker då på att testa men skippa assert, men inte att använda assert fast testa. Borde det inte vara bättre att göra båda saker?

Nej för att asserter != test. assert är en typ av validering som terminerar programmet. Om du har ett program som hantera nätverkstrafik så är det ju vansinne att asserta på en trasig request.

Skrivet av klk:

Och det är väl ingen som använder assert i release kod? då har man missat något i utbildningen

Jag har varit med om fall där en oväntad ändring ledde till aktiverade asserts i release-kod. Jag även varit med om safety-kod där man använt assert som validering eftersom om valideringen misslyckades så kunde det leda till dödlig utgång och därför ville man att applikationen skulle krascha eftersom en krasch av applikationen innebar ett totalstopp av fordonet.

Skrivet av klk:

Jag anar att ni knappt använder debuggern, stämmer det?

Jag använder debuggern för fullt men än en gång debugger(reflektera över namnet debugger) != test. Jag kör standalone gdb och DAP-integration för codelldb i neovim.

Permalänk
Medlem
Skrivet av orp:

Nej för att asserter != test. assert är en typ av validering som terminerar programmet. Om du har ett program som hantera nätverkstrafik så är det ju vansinne att asserta på en trasig request.

Ja eller på linux är det så, men normalt har du då gjort fel och behöver rätta felet. Så varför är det ett problem?
Största fördelen med assert är att det blir en del av koden och att utvecklare omedelbart ser när de gör fel eller man själv kodat fel om aktuell funktionalitet kontrollerar. assert används i princip uteslutande för programmeringsfel så det är test för något annat än funktionalitet.
Tror ingen skulle använda assert för nätverkstrafik eller annat som inte handlar om programmeringsmissar. assert är vanligast för att exempelvis kontrollera att argument är korrekta, får du inte skicka en nullpekare till metod kan du kontrollera med assert, skall värden vara inom vissa gränser så kontrollerar man det och så vidare.

Brukar själv använda assert för rimliga värden. Låt säga att någon har en variabel för längd på något, att längden aldrig är över 100. Att lägga en assert som kontrollerar att värdet är under 10 000 är en teknik för att se att någon inte har skräp i variabeln.

assert öker kvaliteten på allt

Skrivet av orp:

Jag har varit med om fall där en oväntad ändring ledde till aktiverade asserts i release-kod. Jag även varit med om safety-kod där man använt assert som validering eftersom om valideringen misslyckades så kunde det leda till dödlig utgång och därför ville man att applikationen skulle krascha eftersom en krasch av applikationen innebar ett totalstopp av fordonet.

Normalt borde inte assert vara problematiskt i release kod heller men då har ju någon valt att kompilera in debug-information i relasekoden, ibland är det väldigt bra att ha den möjligheten.
Är de så skraja för att råka slå på debuginformation i releasekod gissar jag att det är andra problem.

Att inte ta med assert av den anledningen du nämner är galet, att inte använda assert är galet.

Permalänk
Medlem
Skrivet av orp:

Jag gillar även regressionstestning och som @Erik_T nämnde så är ju unit tester perfekta för detta.

Jag använder också unit-tester till massor utan just unit-teser

Tolkar att ni kör regresionstester med unittester och det kan nog jag göra med, brukar normalt skripta regresionstester men utvecklingsmiljöer har ofta bra stöd för unit-tester så ibland passar sådant där med.

Mest använder jag unit-tester för något lek-kod, brukar kalla det för "PLAYGROUND"

Exempel

set( USE_TEST_ ON ) if( USE_TEST_ ) set(TEST_NAME_ "PLAY_table") add_executable(${TEST_NAME_} ${GD_SOURCES_ALL} ${SOURCE_PLAYGROUND_} "main.cpp" ${external_gd_core} ${external_catch2} "${TEST_NAME_}.cpp" ) target_include_directories(${TEST_NAME_} PRIVATE ${CMAKE_SOURCE_DIR}/external) target_include_directories(${TEST_NAME_} PRIVATE ${CMAKE_SOURCE_DIR}/source) target_compile_definitions(${TEST_NAME_} PRIVATE CATCH_AMALGAMATED_CUSTOM_MAIN _CRT_SECURE_NO_WARNINGS) endif() set( USE_TEST_ ON ) if( USE_TEST_ ) set(TEST_NAME_ "PLAY_folder") add_executable(${TEST_NAME_} ${GD_SOURCES_ALL} ${SOURCE_PLAYGROUND_} "main.cpp" ${external_gd_core} ${external_catch2} "${TEST_NAME_}.cpp" ) target_include_directories(${TEST_NAME_} PRIVATE ${CMAKE_SOURCE_DIR}/external) target_include_directories(${TEST_NAME_} PRIVATE ${CMAKE_SOURCE_DIR}/source) target_compile_definitions(${TEST_NAME_} PRIVATE CATCH_AMALGAMATED_CUSTOM_MAIN _CRT_SECURE_NO_WARNINGS) endif() set( USE_TEST_ ON ) if( USE_TEST_ ) set(TEST_NAME_ "PLAY_strstr") add_executable(${TEST_NAME_} ${GD_SOURCES_ALL} ${SOURCE_PLAYGROUND_} "main.cpp" ${external_gd_core} ${external_catch2} "${TEST_NAME_}.cpp" ) target_include_directories(${TEST_NAME_} PRIVATE ${CMAKE_SOURCE_DIR}/external) target_compile_definitions(${TEST_NAME_} PRIVATE CATCH_AMALGAMATED_CUSTOM_MAIN _CRT_SECURE_NO_WARNINGS) endif()

Dold text
Permalänk
Medlem
Skrivet av Yoshman:

Jo det vet jag därför det inte är svårare att reda ut än att mäta med och utan detta. För mig är det netto positivt.

Vad är det för typ av fel som du kan fånga med enhetstester som inte går med andra typer av tester?

Enligt mig är det bättre att investera den extra tid som det tar att jobba med testerna och istället förbättra koden, det brukar vara rätt mycket tid dessutom för utvecklare som skriver mycket tester är långsamma.

Skrivet av Yoshman:

Hmm... Du har uppenbarligen aldrig ens varit i närheten av säkerhetskritisk kod, t.ex. avionic system certifierade enligt DO-178C.

Måste inte all kod vara säker?
Har i princip uteslutande jobbat med produkter, programvara som säljs till en hel hög kunder. När jag började tryckte vi upp mjukvara på CD, det var dyrt och en mycket arbetsam process för kunder att installera om. Att göra fel i den koden var mer eller mindre katastrof.

Har du 500 CD som skall ut till kunder där de får lägga tid på installera hos användare och så smäller det. Då är man inte kaxig

Permalänk
Medlem
Skrivet av klk:

Måste inte all kod vara säker?
Har i princip uteslutande jobbat med produkter, programvara som säljs till en hel hög kunder. När jag började tryckte vi upp mjukvara på CD, det var dyrt och en mycket arbetsam process för kunder att installera om. Att göra fel i den koden var mer eller mindre katastrof.

Har du 500 CD som skall ut till kunder där de får lägga tid på installera hos användare och så smäller det. Då är man inte kaxig

All kod bör vara säker. Vilket inte alls är samma sak som att all kod måste vara säker, och definitivt inte samma sak som att den faktiskt är säker.

Det är väldigt olika säkerhetskrav på kod som används i t.ex. ett spel eller ett ordbehandlingsprogram, och kod som används i styrsystemet för en jumbojet.
Om ett spel kraschar så är det trist. I värsta fall får man en massa skäll och måste betala tillbaka pengarna till missnöjda kunder.
Om en jumbojet kraschar så är det bokstavligen en katastrof, och sannolikt en massa dödsfall.

Det där du beskriver - kod som distribueras på fysiskt medium till kunder - det var ju det normala för kommersiella program förr i tiden, innan Internet blev vanligt. Det var rätt vanligt med fel av olika slag i programmen på den tiden också - enda skillnaden jämfört med idag var att företagen lade lite mer tid och resurser på att hitta och fixa problem innan man skeppade produkten. Oftast i alla fall.

Permalänk
Skrivet av klk:

Eftersom om du ändrar i kod som har tester skriva mot koden behöver du också skriva om testerna. Det kan till och med vara så illa så att förbättringar i befintlig kod undviks på grund av att utvecklare inte "orkar" skriva om tester (supervanligt)
Ofta är det vanligt att det smäller i tester utan att det är något fel. Finns mycket med unittester som gör att att koden blir seg som sirap att jobba med.

Sorry, men jag förstår fortfarande inte. Hur gör du när du testar din kod? Du skriver att om du ändrar på koden måste du ändra på (unit-)testerna, men det är väl sant oavsett om du gör din testning i form av unit-tester eller regressionstester?

Och varför skulle koden bli långsam av att man testar en enhet i taget? Jag börjar tro att du har en egen betydelse för begreppet unit test. Kanske du kan beskriva vad du tycker att en unit test är, varför koden skulle bli långsammare och varför man efter en ändring i produktionskoden måste ändra på en unit-test men slipper ändra på tester i andra former av testning?

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Sorry, men jag förstår fortfarande inte. Hur gör du när du testar din kod? Du skriver att om du ändrar på koden måste du ändra på (unit-)testerna, men det är väl sant oavsett om du gör din testning i form av unit-tester eller regressionstester?

Det kan säkert vara så att jag använder fel namn, det jag menar med regressionstest är mer resultatet, att någon form av output skall matcha. Typ att en applikation körs igenom eller delar av applikationen och att hela applikationen är byggd för att kunna köras igenom.

Exempelvis via skript, bygga in LUA endast för att testa eller annan teknik. Av det jag prövat har LUA fungerat utmärkt, även byggt kopplingar med Python men python är för mycket runt om och behövs inte för att testa.

Men den tekniken kan man exempelvis bygga skript som stresstestar eller på annat sätt gör idiottester. Dessutom bli det inte extra kod om man räknar bort skript.

Också det enda som jag lyckas testa parallelliserade arbeten med rimlig arbetsinsats.

Permalänk
Medlem
Skrivet av Erik_T:

All kod bör vara säker. Vilket inte alls är samma sak som att all kod måste vara säker, och definitivt inte samma sak som att den faktiskt är säker.

Det är väldigt olika säkerhetskrav på kod som används i t.ex. ett spel eller ett ordbehandlingsprogram, och kod som används i styrsystemet för en jumbojet.
Om ett spel kraschar så är det trist. I värsta fall får man en massa skäll och måste betala tillbaka pengarna till missnöjda kunder.
Om en jumbojet kraschar så är det bokstavligen en katastrof, och sannolikt en massa dödsfall.

Absolut, det är jag med på

För många år sedan anställde vi en programmera som jobbat med mjukvara för satelliter. Och vart avskräckt eftersom det var enorma krav på dokumentation. Mängden kod de producerade var minimal och tycker man det är skoj att programmera bör man inte söka sig till rymden

Annan stor nackdel vilket märktes snabbt är att de inte får träning som man får vid annat kodande där kraven inte är lika stora. Och vill man bli duktig måste man enligt mig skriva mycket kod.

Permalänk
Medlem
Skrivet av klk:

Ja eller på linux är det så, men normalt har du då gjort fel och behöver rätta felet. Så varför är det ett problem?

Mitt exempel hade inget med operativsystem att göra utan att du har programmerat något som ska vara exponerat för omvärlden.
Om du har skrivit en back-end med ett API som ska användas av folk då kan du ju inte krascha varje gång det kommer en trasig request i sådana fall har du ju skapat världen lättaste kod att DDosa och du kommer ha 0% uptime. I ett sådant scenario hade jag undvikit asserter för allt utom möjligen trasig konfiguration.

Skrivet av klk:

Största fördelen med assert är att det blir en del av koden och att utvecklare omedelbart ser när de gör fel eller man själv kodat fel om aktuell funktionalitet kontrollerar.

Fast man ser ju inte det omedelbart. Du måste ju fortfarande köra programmet och återskapa ett scenario som tar förväntad code path. Det fungerar ju fint i fall man har en lite applikation som arbetar ensam helt oberoende av miljön utan input. I mitt exempel med en back-end service så måste du ju säkerställa att alla konfigurerat nätverket på samma sätt och skrivit konfigurationsfilen på samma sätt och satt upp miljövariabler på samma sätt och slänga på en debugger för att se att det smäller på förväntat sätt. Det är många ställen det kan gå fel på i jämförelse med att skriva ett unit test där du skickar in förväntad och icke-förväntad input.

Vad gör du om du ska utveckla en produkt som har 20 systemtjänster som pratar kors och tvärs?

Skrivet av klk:

assert används i princip uteslutande för programmeringsfel så det är test för något annat än funktionalitet.
Tror ingen skulle använda assert för nätverkstrafik eller annat som inte handlar om programmeringsmissar. assert är vanligast för att exempelvis kontrollera att argument är korrekta, får du inte skicka en nullpekare till metod kan du kontrollera med assert, skall värden vara inom vissa gränser så kontrollerar man det och så vidare.

Här säger du först att kolla för programmeringsmissar och sedan pratar du om input-validering genom argument. Vad är det för fel på if (in == NULL) return -1;, istället för att krascha? Om du exempelvis tar emot en FILE* som argument så kommer ju den kunna vara NULL i produktion också där dina asserts var avslagna.

Permalänk
Medlem
Skrivet av orp:

Mitt exempel hade inget med operativsystem att göra utan att du har programmerat något som ska vara exponerat för omvärlden.
Om du har skrivit en back-end med ett API som ska användas av folk då kan du ju inte krascha varje gång det kommer en trasig request i sådana fall har du ju skapat världen lättaste kod att DDosa och du kommer ha 0% uptime. I ett sådant scenario hade jag undvikit asserter för allt utom möjligen trasig konfiguration.

Det var mer än 10 år sedan jag skrev kod som inte skulle fungera på flera operativsystem, men innan det vet jag att på windows kunde man välja "ignore" på assert och köra vidare. Windows har byggt inte mer i operativsystemet för att kontrollera fel. Windows är ett mycket större system jämfört med Linux och kan mer.

Har också motsatt uppfattning till det du skriver om backend, just för att en backend måste vara supersäker måste man också ta till alla metoder man kan för att få säker kod. Och kod skall fungera med eller utan assert i releasekod. Förstår inte vad du menar med att just assert skulle smälla koden, är det fel så är det fel och fångar man inte upp felet innan med funktionalitet och det smäller i assert kommer det ändå bli fel.

Att lösa buggar med en kubernetes installation som startar om serverar ger jag inte mycket för

Skrivet av orp:

Fast man ser ju inte det omedelbart. Du måste ju fortfarande köra programmet och återskapa ett scenario som tar förväntad code path.

Den typen av fel använder du inte assert till. assert är är endast för programmeringsmissar

Permalänk
Medlem
Skrivet av orp:

Fast man ser ju inte det omedelbart. Du måste ju fortfarande köra programmet och återskapa ett scenario som tar förväntad code path.

Denna delen är sann gällande asserts oavsett vad du kodar. Du ser asserten smälla omedelbart när applikationen är uppe och snurrar och du hamnar på en särskild code path. Om man har en komplex applikation så kanske det inte är det inte alltid så lätt att köra den.

Hur verifierar du din kod utöver att strössla den med asserts?

Skrivet av klk:

Windows är ett mycket större system jämfört med Linux och kan mer.

Windows kan så mycket att det enbart används på desktop.

Skrivet av klk:

Förstår inte vad du menar med att just assert skulle smälla koden, är det fel så är det fel och fångar man inte upp felet innan med funktionalitet och det smäller i assert kommer det ändå bli fel.

Vad är fel med if (input == NULL) return -1; istället för en assert?

Permalänk
Medlem
Skrivet av orp:

Vad är fel med if (input == NULL) return -1; istället för en assert?

För att det är ett meningslöst test för ett programmeringsfel. utvecklaren som anropar koden anropar koden på fel sätt och det behöver du inte skriva felhantering för. Räcker med att du fångar upp det med en assert och så får utvecklaren rätta koden och så återkommer inte felet

Permalänk
Datavetare
Skrivet av klk:

Vad är det för typ av fel som du kan fånga med enhetstester som inte går med andra typer av tester?

Det är fel fråga!

Rätt fråga är: finns det något som är mer effektivt än enhetstester för att göra X?

För egen del är svaret "nej" när TDD/enhetstester används på rätt sätt.

Det skrivet så är inte det den enda formen av testing som behövs!

Skrivet av klk:

Enligt mig är det bättre att investera den extra tid som det tar att jobba med testerna och istället förbättra koden, det brukar vara rätt mycket tid dessutom för utvecklare som skriver mycket tester är långsamma.

Man kan använda allt på dåliga sätt. Men rätt använt har TDD, som primärt måste bygga på unit-tester, massor med fördelar som gör att utvecklingen går snabbare med ett bättre resultat.

1. Testerna blir den första användaren av det API man skapar. Är det svårt att skriva tester är det en stark indikation på att APIet är dåligt. Och med TDD är detta något man får väldigt tidigt, innan man ens börjat skriva koden som man testar -> ger snabbare iteration av en de viktigaste delarna (publika APIet).

2. Testerna blir det första lackmustestet av arkitekturen. En "code-smell" här är om mer än en handfull av testerna behöver saker som mock-up och/eller väldigt komplicerad setup/tear-down. En förkrossande majoritet av alla tester bör gå att köra utan mock-ups.

3. Andra former av tester kommer behövas. Rätt gjorda ska tiden det tar att köra alla unit-tester som mest handla om en handfull sekunder. Det gör möjligt att köra den typen av tester hela tiden och det är en enkelt sätt att sätta upp ett specifikt fall man kanske vill undersöka m.h.a. av debugger eller liknande. Finns tester som av nödvändighet kommer ta lite tid att köra, men de ska inte vara unit-tester!

package main import "testing" var input18 = []string{ "2,2,2", "1,2,2", "3,2,2", "2,1,2", "2,3,2", "2,2,1", "2,2,3", "2,2,4", "2,2,6", "1,2,5", "3,2,5", "2,1,5", "2,3,5", } func TestDay18_1(t *testing.T) { world := parseCubeWorld([]string{"1,1,1", "2,1,1"}) numFaces := CountFreeFaces(world.Droplets) if numFaces != 10 { t.Fatalf("Expected 10 free faces, got %d", numFaces) } } func TestDay18_2(t *testing.T) { world := parseCubeWorld(input18) numFaces := CountFreeFaces(world.Droplets) if numFaces != 64 { t.Fatalf("Expected 64 free faces, got %d", numFaces) } } func TestDay18_3(t *testing.T) { world := parseCubeWorld([]string{"0,0,0"}) numFaces := world.CountExteriorFreeFaces(CountFreeFaces(world.Droplets)) if numFaces != 6 { t.Fatalf("Expected 6 free exterior faces after filling with water, got %d", numFaces) } } func TestDay18_4(t *testing.T) { world := parseCubeWorld(input18) numFaces := world.CountExteriorFreeFaces(CountFreeFaces(world.Droplets)) if numFaces != 58 { t.Fatalf("Expected 58 free exterior faces after filling with water, got %d", numFaces) } }

Unit-tester ska inte behöva vara mer komplicerade än så här, detta råkar vara tester för Advent of Code 2022, dag 18
Edit: Då debuggern är ett väldigt bra och kraftfullt verktyg är det rätt naturligt att utvecklingsmiljöer gör det trivialt att debug:a ett specifikt test eller benchmark (mikrobenchmarks är typiskt väldigt lika unit-tester). Unit-tester/benchmarks är del av standard tool-chain i Go, vilket gör det naturligt för VS Code och liknande att integrera detta
Skrivet av klk:

Måste inte all kod vara säker?
Har i princip uteslutande jobbat med produkter, programvara som säljs till en hel hög kunder. När jag började tryckte vi upp mjukvara på CD, det var dyrt och en mycket arbetsam process för kunder att installera om. Att göra fel i den koden var mer eller mindre katastrof.

Finns två typer av säkerhet.

"Safety", skydda världen från programvaran/systemet. Är primärt detta man behöver garantera med de programvaror som kräver certifiering för att få användas.

"Security" är den andra formen där programvaran/systemet skyddas från världen. I de säkerhetskritiska fallen är nog detta rätt ofta löst genom att dessa system körs på isolerade system som är certifierade i sin helhet.

Vad dessa certifieringsmetoder visat är att men tillräckligt grundligg testing är det fullt möjligt att skriva nära nog perfekt programvara. I DO-178C är det inte ens C/C++ koden man certifierar, det är den assembler som faktiskt kör och kravet på de högsta nivåerna är 100 % line- (finns det instruktioner som inte körs ska de bort alt. så får man skriva en rapport på varför instruktionen finns när den inte körs) och state-coverage (d.v.s. varje villkorat hopp måste ha testfall för alla möjliga utfall).

Så det är i praktiken "perfekt" programvara, men enda sättet vi vet hur man kan skapa detta idag är så löjligt dyrt att det inte är användbart utanför de fall där den nivån är ett hårt krav.

Skrivet av klk:

För att det är ett meningslöst test för ett programmeringsfel. utvecklaren som anropar koden anropar koden på fel sätt och det behöver du inte skriva felhantering för. Räcker med att du fångar upp det med en assert och så får utvecklaren rätta koden och så återkommer inte felet

Finns massor med anledningar varför det i praktiken inte alls är så enkelt och varför det kan vara fullt vettigt att även i release-läget ha kod som upptäcker fall som "inte borde hända".

För inte hävdar du att normalkodnivån är nära nog perfekt programvara???

I debug kan man då på en lite högre nivå just bara göra "assert(X)" för att få information om felet och försöka fixa det.

I release kan det vara så att man på en högre nivå har extra kontext. Man har nu konstaterat ett fel som t.ex. resulterat i att någon beräkning inte kan göras.

Om man måste ha resultatet finns inget annat att göra än att döda programmet och logga felet.

Men kan finnas andra fall där en sådant fel mest ger lite irritation, i det läget vill kan fortfarande avbryta i debug (för målet är att fixa felet) men i release kan man välja att köra vidare (vilket t.ex. leder till att inget händer när man trycker på en UI-knapp eller liknande) då det är mindre dåligt för upplevelsen än att döda hela programmet.

Då kan man inte använda asserts() för huvudsyftet med dessa är att testa saker som måste vara sanna, om de inte är det har programmet hamnat i ett tillstånd där det inte finns någon poäng att fortsätta -> enda vettiga är att logga felet och avsluta.

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:

Så det är i praktiken "perfekt" programvara, men enda sättet vi vet hur man kan skapa detta idag är så löjligt dyrt att det inte är användbart utanför de fall där den nivån är ett hårt krav.

Exakt, det är dyrt vilket är en konsekvens av att programmerare aldrig blir klara. De trasslar i sin i massa test, koden blir segare och segare att jobba i tills projektet kraschar.

Så länge det är simpla saker kanske de lyckas få fram något men räkna med mängder med arbetstimmar

Det är därför enhetstester är totalt värdelöst

Skrivet av Yoshman:

För inte hävdar du att normalkodnivån är nära nog perfekt programvara???

Verkar det så ? Är det inte för att jag påstår att det mesta är skräp som jag gjort mig mindre populär i tråden, programmerare idag lär sig inte programmera.

Det är så mycket "så här skall du göra" och så gör de så utan att ifrågasätta varför. När de lär sig hur man skall göra utan att veta varför så lär man sig inte och de får heller inte öva på saker som är så viktiga för att skriva bra kod.

Permalänk
Datavetare
Skrivet av klk:

Exakt, det är dyrt vilket är en konsekvens av att programmerare aldrig blir klara. De trasslar i sin i massa test, koden blir segare och segare att jobba i tills projektet kraschar.

Så länge det är simpla saker kanske de lyckas få fram något men räkna med mängder med arbetstimmar

Det är därför enhetstester är totalt värdelöst

Verkar det så ? Är det inte för att jag påstår att det mesta är skräp som jag gjort mig mindre populär i tråden, programmerare idag lär sig inte programmera.

Va? Om det gör enhetstester värdelösa är i så fall även asserts helt värdelösa då de inte täcker 100 % av alla tänkbara fall!

Vad saker som Modified Condition/Decision Coverage visar är att det är möjligt att utföra testning på en sådan grundlig nivå att man kan bevisa att koder gör vad den är designat att göra. Men det är inte något man kan använda i det allmänna fallet då det är väldigt dyrt/arbetskrävande.

När unit-tester används för t.ex. TDD är man normalt sett inte i närheten någon perfekt "state-coverage". Det är inte heller målet, huvudmålet här är att på ett snabbt/effektivt sätt kunna testa APIet, verifiera att förändringar av koden inte ändrat externt observerat beteende, ge snabb access till fall där man vill undersöka koden m.h.a. debugger, etc.

Likt det mesta kräver lyckad användning av TDD att de inblandade har rätt kunskap. Precis som de iblandade behöver ha rätt kunskap om det/de programspråk och bibliotek som används för att det ska bli bra.

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:

Finns massor med anledningar varför det i praktiken inte alls är så enkelt och varför det kan vara fullt vettigt att även i release-läget ha kod som upptäcker fall som "inte borde hända".

Och det finns massor med anledningar till varför man inte skall testa "allt". I exemplet returnerades -1.
Bara där har det spårat ur eftersom "vad är -1". I release måste man ha kod som gör att det är möjligt att få tillräcklig med information om vad som är problem. Det blir mängder med kod ändå för att granska och ha bra felhantering utan att testa för saker som är rena programmeringsbuggar.

Permalänk
Medlem
Skrivet av Yoshman:

Va? Om det gör enhetstester värdelösa är i så fall även asserts helt värdelösa då de inte täcker 100 % av alla tänkbara fall!

Och ingen har sagt det heller, assert använder du för att fånga upp programmeringsfel, det är allt.

Permalänk
Datavetare
Skrivet av klk:

Och det finns massor med anledningar till varför man inte skall testa "allt". I exemplet returnerades -1.
Bara där har det spårat ur eftersom "vad är -1". I release måste man ha kod som gör att det är möjligt att få tillräcklig med information om vad som är problem. Det blir mängder med kod ändå för att granska och ha bra felhantering utan att testa för saker som är rena programmeringsbuggar.

Ska inte tala allt för mycket för någon annan, men är 100 % säker att just det bara var ett exempel.

Ett mer "production ready" fall skulle kasta exception (om man gillar det, personligen anser jag att exception är goto-on-steriods och undviker det så långt som möjligt) eller ha en signatur där man returnerar ett värde när det går bra (Some(X) i Rust, icke-null nullable type i C#, std::optional<T> med ett värde i C++) och inget värde när det går dåligt. Sedan får högre nivå göra lämplig sak när det inte blev något värde.

Visa signatur

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

Permalänk
Datavetare
Skrivet av klk:

Och ingen har sagt det heller, assert använder du för att fånga upp programmeringsfel, det är allt.

Fast med din logik kring varför unit-tester är värdelös så blir även användning av assert helt meningslöst.

Unit-tester löser inte allt, men det finns saker de löser bättre än något annat och för det ska man använda dem.

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:

Exakt, det är dyrt vilket är en konsekvens av att programmerare aldrig blir klara. De trasslar i sin i massa test, koden blir segare och segare att jobba i tills projektet kraschar.

Så länge det är simpla saker kanske de lyckas få fram något men räkna med mängder med arbetstimmar

Det är därför enhetstester är totalt värdelöst

WTF. @Yoshman skriver om att det är dyrt att certifiera programvara, på den nivån att den genererade koden granskas instruktion för instruktion. Då håller du med men lägger till att det beror på att programmerarna testar för mycket!?! Och att koden blir långsam för att de testar??? Hur tänkte du nu?