Jsem v nesnázích. Pracuji v úložišti, které v rámci svých funkcí provádí mnoho změn databáze.

Funkce, kterou mám na starosti, vrací responseids (ale z transformace, ne z jakékoli akce databáze). Jako vedlejší efekt však přidá do databáze objekt obsahující tyto responseIds.

Takže bych to měl pojmenovat:

  • getResponseIds: Toto zvýrazní návratové hodnoty. Je to velmi funkční způsob myšlení, ale pokud mám funkci postToDB, nemá smysl používat getStatusOfPost
  • addResponseIdToDB: Tím se zvýrazní vedlejší efekt, i když si opravdu myslím, že mnoho mých funkcí funguje pouze v databázi (a nemá tendenci nic vracet)
  • getAndAddResponseIdsToDB: Velmi poučné, ale velmi dlouhé.

Jaké jsou výhody a nevýhody výše uvedených návrhů? Nebo můžete sami navrhnout lepší návrh?

Komentáře

  • Co třeba persistResponseIds?
  • Možná vás překvapí, jak daleko se funkční dav dostal s ekvivalentem getStatusOfPost 🙂
  • getAndSaveResponseIds
  • responseIds = createResponseIds() vypadá jasně a stručně. get() Něco, co předtím neexistovalo ‚, takže create je vhodné sloveso. Nově vytvořený obsah je to, co ‚ očekáváte, že se funkce create() vrátí. Nebo mi možná ‚ chybí něco zjevného?
  • @fattie Souhlasím s tím, že kód by měl být komentován sám. Komentáře by vám neměly říkat, co kód dělá. Komentáře by vám měly sdělit, proč kód existuje. Pokud refaktorování kódu znamená refaktorování jeho ‚ s komentářů, máte špatné komentáře. Souhlasím s tím, že jména mohou být dlouhé celé věty. Dobré jméno by mělo dál hledat uvnitř funkce, aby vás nepřekvapilo. Neměl by vám ‚ říkat, jak to implementovat. Mělo by vám sdělit, co klient očekává. Udělejte to a máte dobrou abstrakci.

Odpověď

Název funkce, který obsahuje and je na špatné úrovni abstrakce .

Přikláním se k addResponseIdToDB(), protože jinak je „vedlejší efekt“ úplným překvapením. Avšak:

responseIds = addResponseIdToDB(); 

nikoho nenechá překvapeného.

Princip segregace odpovědnosti v dotazu na příkazové příkazy tvrdí, že by to neměl být jediný způsob, jak získat objekt responseId. Také by měl existovat dotaz, který nezmění DB, který může získat tento objekt.

Na rozdíl od Bertrand Meyer si nemyslím, že to znamená, že doplněk musí vrátit neplatnost. Prostě by měl existovat ekvivalentní čistý dotaz. a lze je snadno najít, aby se databáze zbytečně nezneužila pomocí dotazů na změnu stavu.

Vzhledem k tomu, že getResponseIds() by měl existovat a nemluvit s databází, nejlepší název metody, která dělá obojí, je ve skutečnosti addToDB(getResponseId()). Ale to je jen to, jestli o tom chcete získat veškeré funkční složení.

Komentáře

  • Přidání k tomu, co bylo řečeno, ale přidáním slova, které nebylo ‚ použito, bych řekl, že “ a “ je vhodné, když funkce dělá něco, co je atomové . Pokud je možné získat výhodu ze dvou věcí, které se dějí atomicky / společně / najednou, pak je explicitní s tím, co jsou tyto dvě věci ve funkci jméno je dobré. Souhlasím tedy s vaším prvním prohlášením obecně, ale bez jakékoli kvalifikace nesouhlasím.
  • … nikoho nenechává překvapen. „. Nesouhlasím, ‚ m jsem překvapen, že se booleovská proměnná nazývá responseIds a pak musím udělat mentální posun, abych si uvědomil, že přidává a dostává vše v jednom. Ale nesouhlasím s @tintintong, že getAndAddResponseIdsToDB je to moc dlouhé; to ‚ má zhruba polovinu délky mnoha mých názvů funkcí. Pokud funkce dělá dvě věci, řekněte to jejím jménem.
  • @Luaan OK, na co tedy přejmenujete getAndIncrement? otherIncrement?
  • @Luaan Takže jakou hodnotu Increment vrátí, hodnotu před přírůstkem nebo po přírůstku? ‚ není jasné, které by to byly, aniž byste se ponořili do dokumentů.Myslím, že incrementAndGet a getAndIncrement jsou mnohem lepší názvy metod, což podle mého názoru dělá dobrý důvod pro “ A “ v názvech metod, alespoň v konkrétním případě metod, které mají vedlejší účinky, které by mohly mít vliv na návratovou hodnotu ..
  • @Luaan Když řeknete “ Přírůstek vrátí zvýšenou hodnotu “ máte na mysli hodnotu před přírůstkem? Nejprve jsem vás nepochopil. což je ve skutečnosti skvělý příklad toho, proč getAndIncrement a incrementAndGet jsou lepší jména než jen increment, i když je to posuzováno jednotlivě

odpověď

Jak již zmínili ostatní, použití and v názvu funkce automaticky znamená, že funkce dělá alespoň dvě věci, což obvykle naznačuje, že dělá příliš mnoho nebo něco dělá na špatném místě.

Použití klauzule and v názvu funkce však podle mých zkušeností může dávat smysl, když v určitém toku existují určité kroky, které je třeba provést postupně, nebo až bude mít celý výpočet smysl.

V numerických výpočtech to může mít smysl:

normalizeAndInvert(Matrix m)

Chci říct, kdo ví, že? Pokud potřebujete vypočítat nějaké … řekněme, trajektorie osvětlení v počítačové grafice a na ve fázi musíte normalizovat a invertovat určitou matici a zjistíte, že neustále píšete:

m = normalize(m), následovaný invert(m), stejně jako jednoduchý příklad, představující abstrakci normalizace a invertování, může být dobrý z hlediska čitelnosti.

Sémanticky řečeno, věci jako divideAndConquer() atd., je pravděpodobně odrazeno od výslovného napsání, ale And je v zásadě nezbytný.

Komentáře

  • Funkce pravidelně provádějí více než jednu věc, ale měly by to být maličkosti, které doplňují jednu velkou věc, kterou ‚ má smysl na vyšší úrovni. normalizeAndInvert může být computeLighting a divideAndConquer může být applyMachiavelli
  • Je zřejmé 🙂 Stačí uvést, že nejprve vytvoření funkce s “ a “ v názvu může přijít jako přirozená abstrakce založená na konkrétním kontextu. Refaktoring pomocí “ Metoda přejmenování “ by měla přijít bezprostředně poté;)
  • @BrunoOliveira Kromě těchto dvou kroků jsou samy o sobě součástí mnoha věcí, přejmenování není správným přístupem ‚. A mělo by to být vzácné, ale nikdy jej nepoužívat znamená, že se ‚ opakujete.

Odpovědět

Řekl bych, že je to obecně v pořádku, ale není to přijatelné ve všech případech.

Dalo by se například argumentovat proti and ve jménu funkce založené na principu jediné odpovědnosti alias S v SOLID – protože and by mohl naznačovat více odpovědností. Pokud and opravdu znamená, že funkce dělá dvě věci, pak si pravděpodobně budete chtít pečlivě promyslet, co se děje.

Příklad knihovny, která využívá and v názvech funkcí lze nalézt v prostředí Java „s souběžnosti a zde and je ve skutečnosti velmi důležitou součástí toho, co se děje, a úzce odpovídá tomu, co popisujete ve svém příspěvku, kde je stav změněn a stav je vrácen. Takže jasně existují někteří lidé ( a některé případy použití), kde je to považováno za přijatelné.

Komentáře

  • and může znamenat více odpovědností „. A v tomto případě to skutečně naznačuje. Funkce odněkud získá některá ID odpovědí, zapíše je do databáze a je vrátí. Potřeba toho “ a “ by ve skutečnosti měla přinejmenším v OP vyvolat myšlenku, že jsou potřeba dvě funkce: jedna pro získání ID a jeden, který je zapíše do databáze.
  • I když souhlasím s tím, že and je vůně kódu, základní chování se zdá být legitimní: obecně to není špatné Myšlenka vrátit nějaké další hodnoty z metody, která je nezbytně nutná (mezilehlé) výsledky provádění její hlavní funkce. Pokud je hlavní funkcí této metody přidání ID odezvy do databáze, dodatečné vrácení ID, které přidal volajícímu, je jen čistou a bez námahy použitelnou funkcí metody.
  • Nemyslím si ‚, že to nutně porušuje SRP. Vždy budete potřebovat funkce, které dělají více věcí. Důležitou součástí je, aby tyto funkce volaly jinou funkci pro každou věc, kterou chtějí dělat, místo aby přímo obsahovaly požadovaný kód.
  • Pokud funkce dělá dvě věci, měl by to název odrážet.

Odpověď

Tahle otázka je opravdu těžko zodpověditelná, jak dokazuje řada komentářů. Zdá se, že lidé mají protichůdné názory a rady o tom, co je dobré jméno.

Chtěl bych přidat 2 centy k tomuto 2měsíčnímu vláknu, protože si myslím, že mohu přidat více barev k tomu, co již bylo navrženo.

Pojmenování je proces

To vše mi připomíná vynikajícího průvodce šesti kroky: Pojmenování jako proces .

Špatný název funkce je název, který je překvapivý a vy si uvědomíte, že mu nemůžete důvěřovat. Dobré pojmenování je těžké získat hned na první výstřel. Se zkušenostmi je to snazší.

6 iterativních kroků k vytvoření dobrého jména

  1. Nahraďte překvapivé jméno zjevným nesmyslem jako appleSauce(). Zní to hloupě, ale je to dočasné a je zřejmé, že tomuto jménu nelze důvěřovat.
  2. Získejte čestné jméno na základě toho, co chápete z toho, co funkce dělá. Řekněme, že jste dosud nerozuměli vložení do části DB, getResponseIdsAndProbablyUseDb by byla volba.
  3. Získat zcela upřímný , takže název funkce říká vše, co funkce dělá (getAndAddResponseIdsToDB nebo getResponsesButAlsoAddCacheOfTheResponsesToTheDb from @Fattie are great examples)
  4. Get to „does the right thing“ což je v zásadě část, kde jste rozdělili svou funkci podél „AND“. Takže ve skutečnosti máte getResponseIds a addResponseIdsToDb.
  5. Přejděte k názvu „Intention Revealing“ , který řeší bod „Vždy chci získat ID odpovědi I vloženo do DB poté, co tak učiním „. Přestaňte přemýšlet o podrobnostech implementace a vytvořte abstrakci, která používá 2 nejmenší funkce k vytvoření něčeho jiného. Toto je úroveň vyšší abstrakce, kterou zmiňuje @candied_orange. xample createResponseIds by to dokázal a bude složením getResponseIds a addResponseIdsToDb.
  6. Přejít na abstrakci domény . To je těžké, záleží na vašem podnikání. Poslech vašeho obchodního jazyka vyžaduje čas, abyste se dostali správně. Nakonec můžete skončit s konceptem Response a Response.createIds() by dávalo smysl. Nebo je možná ResponseId něco cenného a měli byste továrnu na vytváření mnoha. Vložení do DB by bylo implementačním detailem úložiště atd. Ano, design by byl abstraktnější. Bylo by bohatší a umožnilo vám vyjádřit více. Nikdo mimo váš tým vám neřekne, jaká správná abstrakce domény by ve vaší situaci měla být. Záleží .

Ve vašem případě jste již zjistili 1 a 2, takže byste pravděpodobně měli jít alespoň na 3 (použijte „AND“) nebo dále. Ale jít dále není jen otázka pojmenování, ve skutečnosti byste si rozdělili odpovědnosti.

Tudíž jsou zde platné různé návrhy.

V podstatě:

  • Ano, překvapivé názvy funkcí jsou hrozné a nikdo se tím nechce zabývat
  • Ano, „AND“ je v názvu funkce přijatelné, protože je lepší než zavádějící název
  • Ano, úroveň abstrakce je související koncept a záleží na tom.

Nemusíte hned jít na 6. fázi, je dobré zůstat na fáze 2, 3 nebo 4, dokud nebudete vědět lépe!


Doufám, že by bylo užitečné poskytnout jiný pohled na to, co vypadá jako protichůdné doporučení. Věřím, že každý usiluje o stejný cíl ( nepřekvapivá jména), ale zastavte se v různých fázích na základě jejich vlastních zkušeností.

Rádi zodpovíme, pokud máte nějaké dotazy 🙂

Odpověď

Vaše funkce umožňuje dvě věci:

  1. Získá sadu ID prostřednictvím transformace a vrátí je volajícímu,
  2. Zapíše tuto sadu ID do databáze.

Pamatujte si zde princip jediné odpovědnosti: měli byste se zaměřit na funkci mít jednu odpovědnost, ne dvě. Máte dvě odpovědnosti, takže máte dvě funkce:

getResponseIds – získá sadu ID prostřednictvím transformace a vrátí je volajícímu
addResponseIdToDB – Vezme sadu ID a zapíše je do databáze.

A zmizí celá otázka toho, co nazývat jedinou funkcí s více zodpovědnostmi, a zmizí i pokušení umístit and do názvů funkcí.

Jako další bonus, protože stejná funkce již není odpovědná za dvě nesouvisející akce, lze getResponseIds přesunout z vašeho repo kódu (kam nepatří protože neprovádí žádnou činnost související s DB), do samostatné třídy / modulu na obchodní úrovni atd.

Komentáře

  • To ‚ s jistě pravda, ale zjistíte, že opakujete úryvek pomocí těchto dvou metod SRP mnohokrát, pak byste pravděpodobně měli napsat triviální metodu, která to udělá, abyste DRY, neměli ‚ Jste?
  • @maaartinus, pokud zjistíte, že tyto dvě metody voláte na mnoha místech, pravděpodobně máte problém s nedostatečnou soudržností kódu. Vytvoření funkce “ DRY “ pak tento nedostatek soudržnosti pouze maskuje.

Odpověď

Mít složený název funkce je přijatelné, takže to, jaké schéma pojmenování použijete, závisí na vašem kontextu. Existují puristé, kteří vám řeknou, abyste to rozešli, ale já budu tvrdit jinak.

Existují dva důvody, proč se těmto věcem snažit vyhnout:

  • Čistota – funkce která dělá dvě věci, by měla být převedena na dvě funkce, které dělají jednu věc.
  • Lexikální velikost – bigUglyCompositeFunctionName se těžko čte.

Argument čistoty je obvykle ten, na který se zaměřujeme. Jako nejasná obecná heuristika je rozdělení funkcí dobrá věc. Pomáhá rozdělit to, o co jde, a usnadňuje pochopení. Je méně pravděpodobné, že budete dělat „chytré“ triky se sdílením proměnných, které vedou ke spojení mezi těmito dvěma chováními.

Takže si musíte položit otázku: „Měl bych to stejně udělat?“ Říkám, že dělení věcí je vágní heuristika, takže proti tomu opravdu potřebujete jen slušný argument.

Jedním z hlavních důvodů je to, že je prospěšné považovat tyto dvě operace za jednu. Konečný příklad toho lze nalézt v atomových operacích: compare_and_set. compare_and_set je základním stavebním kamenem atomů (což je způsob, jak provádět multithreading bez zámků), který je natolik úspěšný, že mnozí jsou ochotni o něm uvažovat jako o základní kámen. V tom jménu je „a“. Existuje pro to velmi dobrý důvod. Celý bod této operace spočívá v tom, že provádí srovnání a nastavení jako jednu nedělitelnou operaci. Pokud jste to rozdělili na compare() a set(), můžete porazit celý důvod, proč funkce existovala, protože dvě compares() se může objevit zády k sobě před set() s.

Vidíme to také ve výkonu. Můj oblíbený příklad je fastInvSqrt . Toto je slavný algoritmus od Quake, který počítá 1 / sqrt (x). Kombinujeme operace „inverzní“ a „druhá odmocnina“, protože to dává nám přináší obrovské zvýšení výkonu. Provádějí Newtonovu aproximaci, která provádí obě operace v jednom kroku (a dělá to v celočíselné matematice, spíše než s plovoucí desetinnou čárkou, na které v té době záleželo). Pokud byste udělali inverse(sqrt(x)), bylo by to mnohem pomalejší!

V některých případech je výsledek jasnější. „Napsal jsem několik API zahrnujících threading, kde člověk musí být strašně opatrný ve věcech, jako jsou uváznutí. Nechtěl jsem, aby si můj uživatel byl vědom podrobností o interní implementaci (zejména proto, že je mohu změnit), takže jsem napsal API s několik funkcí „a“, které bránily uživateli v nutnosti držet zámek pro více než jedno volání funkce. To znamená, že nikdy nepotřebovali vědět, jak zacházím s vícevláknovou synchronizací pod kapotou. Ve skutečnosti většina mých uživatelů ani nevěděla, že jsou v prostředí s více podprocesy!

Takže i když je obecným pravidlem, že věci rozdělit, vždy může existovat důvod, proč je spojit dohromady. Například , může váš uživatel rozbít vaši architekturu přidáním do databáze několikrát, aniž by se mezi nimi „dostalo“? Pokud každá z odpovědí zaznamenaných v DB potřebuje mít jedinečný identifikátor, můžete se dostat do potíží, pokud je uživatel bude chtít udělat nilly. Podobně byste někdy chtěli nechat uživatele „dostat se“, aniž byste zaznamenali výsledky do databáze? Pokud je odpověď „ano“, rozdělte je tak, aby měl uživatel přístup k funkci „získat“. Pokud však zabezpečení vaší aplikace je přerušeno, pokud se uživatel může „dostat“, aniž by byl výsledek zaznamenán do databáze, funkce byste měli udržovat pohromadě.

Pokud jde o lexikální problémy, název vaší funkce by měl popisovat, co uživatel o tom potřebuje vědět. Začněme částí „získat“.Je docela snadné odstranit „get“ z názvu funkce, protože všechny vaše příklady budou zobrazovat přiřazení: int id = addResponseIdToDB() „. Na všech místech, kde se funkce používá, skončíte nahoru dokumentující skutečnost, že funkce vrátila hodnotu.

Podobně „add“ může být nepovinné. Pojem „vedlejší efekt“ používáme jako všeobjímající výraz, ale existují jeho různé odstíny. Pokud jsou položky DB pouze protokolem, nemusí být důvod je zvýrazňovat. Nikdy nevidíme funkce jako playMusicAndSendPersonalInformationToOurCorporateServers. Je to jen playMusic a pokud máte štěstí, může dokumentace zmínit něco o připojení k soketu přes internet. Na druhou stranu, pokud se od uživatelů očekává, že tuto funkci budou volat za účelem přidávání věcí do DB, pak je „add“ zásadní. Nevytahujte to.

Nyní jsem napsal mnoho důvodů, proč udělat každou možnou kombinaci toho, na co se ptáte. Záměrně jsem na otázku neodpověděl, protože existuje možnost volby. Řídit se není pravidlem. Vytváříte rozhraní API.

Jak již bylo řečeno, můj instinkt spočívá v tom, že addResponseIdToDB bude pravděpodobně nejlepší odpovědí. Ve většině případů je část „dostat“ dostatečně zřejmým vedlejším účinkem, který nezískává další hluk způsobený jejím všude. Je však několik míst, kde bych to mohl považovat za důležité:

  • Pokud je „get“ drahé – Pokud musíte udělat „get“, které zahrnuje načtení něčeho přes internet a jeho přidání do místní mezipaměti DB, je v každém případě důležité „get“. To je věc, o kterou se uživatel snaží.
  • Pokud potřebujete objasnit, že uživatel musí věnovat pozornost hodnotě. Pokud chce uživatel proměnnou použít, „uvědomí si, že ji API vrací, a použije ji. Chcete si však dát pozor na uživatele, který neví, že to potřebuje. Například pokud budete muset tuto operaci „zavřít“ pomocí ID později, abyste uvolnili paměť, možná budete chtít upozornit na skutečnost, že „něco dělám. V těchto případech se možná budete chtít podívat na jiné sloveso než „dostat“. „get“ často implikuje idempotentní funkce (opětovné volání nic nedělá). Pokud vrací prostředky, jsou hezké i další slovesa jako „create“ nebo „obtain“. Tento konkrétní mechanismus selhání je hlavním problémem v C při zpracování výjimek . C postrádá mechanismus chycení / hodu C ++, takže se spoléhá na návratové kódy. Vývojáři jsou slavní jednoduše proto, že tyto návratové kódy nekontrolují a kvůli tomu se dostanou do opravdu špatných situací, jako je přetečení vyrovnávací paměti.
  • Symetrie – Někdy navrhujete rozhraní API tak, aby k němu měla lexikální symetrii. Slova nastavujete tak, aby pocházela ve dvojicích nebo jiných vzorech, a vytvářejte příkazy tak, aby bylo možné snadno vizuálně identifikovat ať už byl vzor dodržen nebo ne. Řekl bych, že je to vzácné, ale není to neslýchané. Proto zavírání značek XML opakuje název značky (například < foo > a < / foo >).

Komentáře

  • Pro lidi, kteří ‚ neznáme matematiku: 1 / x i sqrt (x) jsou poměrně pomalé funkce. Pomocí chytré matematiky můžeme vypočítat o 1 / sqrt (x) rychlejší než dělení nebo druhá odmocnina. Vlastně mnohem rychlejší, že nejrychlejším způsobem výpočtu sqrt (x) je výpočet 1 / sqrt (x) pomocí chytré implementace a vynásobení výsledku x.
  • Stejně jako ve fyzice, kde základní jednotky už nejsou metr a sekunda, ale sekunda a rychlost světla, protože rychlost světla můžeme měřit s větší přesností než délka metru.

Odpověď

Co je hlavní záměr této metody od? Proč přidávat tato transformovaná ID do DB, je to z důvodu ukládání do mezipaměti? Budu pracovat za tohoto předpokladu.

Vypadá to, že záměrem metody je opravdu jen získat transformovaná ID odpovědí (buď transformaci nebo jejich získání z mezipaměti), a tak existuje název vaší metody:

getTransformedResponseIds nebo méně podrobně getResponseIds()

Metoda s tímto názvem může ukládat do mezipaměti nebo možná ne, a to lze zdokumentovat, ale váš název metody by vás neměl spojovat s konkrétní implementací; Co když se rozhodnete přestat používat DB a místo toho je ukládat do mezipaměti jinde, například jen dočasně v paměti?

Vedlejšími účinky by mělo být právě to, vedlejší účinky, měly by být pravděpodobně zdokumentovány, ale neměly by skutečně ovlivnit základní záměr (nebo úspěch) nebo název funkce. Pokud získání hodnoty z mezipaměti selže (nebo pokud nakonfigurujete přeskočení ukládání do mezipaměti), což by nemělo být kritickým problémem, měla by metoda pouze transparentně přepočítat, uložit do mezipaměti (nebo ne) a vrátit novou hodnotu.

Někdy je použití „AND“ užitečné k vyjádření záměru, například u metod Java getAndIncrement a incrementAndGet tak to rozhodně není mimo stůl.

Odpověď

Říkáte, že funkce něco vrací „z transformace, nikoli z any db action „.

To naznačuje, že se funkce chová spíše jako konstruktor než jako getter. konstruktory by však také neměly způsobovat vedlejší účinky (děkujeme za odkaz, @ MechMK1 ).

Na druhou stranu tovární metody již předpokládají určitou úroveň nepořádku . Jednou z motivací pro použití továrních metod je například to, že tovární metoda:

Umožňuje čitelnější kód v případech, kdy existuje více konstruktorů, každý pro jiný důvod. – wikipedia

Stejně tak

Pokud potřebujete pracovat s vedlejšími účinky, lze tovární metodu pojmenovat tak, aby bylo jasnější, o jaké vedlejší účinky jde. – ruakh

Zvažte vytvoření této funkce jako tovární metody pomocí výrazu „loged“, který programátory upozorní na úložiště databáze:

  • Prohlášení: createLoggedResponseid(...) {...} // log object to db
  • Volejte: responseid = createLoggedResponseid(...);

Komentáře

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *