NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Návrh: Jaký je správný způsob udělat možnost uvést buď žádný, nebo jeden ze dvou parametrů metody?

V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Petr Šťastný
Tvůrce
Avatar
Petr Šťastný:5.1.2018 15:25

Ahoj,

udělal jsem wrapper pro jedno API a informace requestuji z URL

api.crapi.com/endpoint/data

API vrací objekt v JSONu. Objekt je velký, v JSONu na tisíce řádků. Proto byla přidána funkce, že na konec URL můžu (nemusím) dát query string: buďto ?keys= nebo ?exclude=, Musím uvést buďto žádný query string, nebo právě jeden z těch dvou. Keys= specifikuje v CSV formátu, které vlastnosti objektu chci dostat z API, kdežto Exclude= specifikuje v CSV formátu, které vlastnosti z API dostat nechci.

Jakým způsobem to mám udělat návrhově?

Teď mám metodu GetProfile(string name), která vrací profil s daným jménem. Napadly mě dvě řešení, jak implemenotvat keys a exclude:

  1. udělat dvě metody - GetProfileInclude(string name, params string[] includeFields) a GetProfileExclude(string name, params string[] excludeFields) - toto mi přijde jako špatné řešení, nehledě na to, že endpointů je víc a bylo by to zmatené
  2. udělat vše v jedné metodě - třeba GetProfile(string name, string[] include, string[] exclude) (jedno pole musí být null) nebo GetProfile(string name, params string[] fieldNames, bool include) (bool určuje, jestli chci include, nebo exclude funkci)

Jakým způsob je vhodné tohle udělat?

Díky, Petr

 
Odpovědět
5.1.2018 15:25
Avatar
Jan Vargovský
Tvůrce
Avatar
Jan Vargovský:5.1.2018 15:44

Jednoduše, nepoužíváš žádný potupný jazyk, kde musíš tohle přetěžování řešit v kódu.

GetProfileInclude(string name, string[] include = null, string[] exclude = null)
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
5.1.2018 15:44
Avatar
hanpari
Člen
Avatar
Odpovídá na Petr Šťastný
hanpari:5.1.2018 23:00

Dost dobré!
Ale nevím, jak to řeší tvůj problém?

>> Musím uvést buďto žádný query string, nebo právě jeden z těch dvou.

https://gist.github.com/…2299f74affcc

Neco mi asi unika...

To co ve skutečnosti potřebuješ je toto

http://xoofx.com/…s-in-csharp/

ale zda se, ze ten jazyk je prilis potupny na to, aby to podporoval :)

Editováno 5.1.2018 23:00
 
Nahoru Odpovědět
5.1.2018 23:00
Avatar
gcx11
Tvůrce
Avatar
Odpovídá na hanpari
gcx11:6.1.2018 0:12

Jeden z těch optional parametrů neuvede:

GetProfile(string name, include: new string[]{"include"})
GetProfile(string name, exclude: new string[]{"exclude"})

ale samozřejmě může zadat oba dva anebo žádný, což by musel kontrolovat v metodě.

Editováno 6.1.2018 0:12
 
Nahoru Odpovědět
6.1.2018 0:12
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na hanpari
Jan Vargovský:6.1.2018 1:09

Explicitně jsem to tam nepsal. Ofc může zadat oba, ale to si odchytí interně v metodě.

 
Nahoru Odpovědět
6.1.2018 1:09
Avatar
hanpari
Člen
Avatar
Odpovídá na Jan Vargovský
hanpari:6.1.2018 8:10

No dobre, a co pak, kdyz zada i include i exclude? Vyhodis vyjimku? Nebo si vyberes pouze jeden parametr? Nebo zahodis oba dva?

 
Nahoru Odpovědět
6.1.2018 8:10
Avatar
hanpari
Člen
Avatar
Odpovídá na Petr Šťastný
hanpari:6.1.2018 13:38

Osobně by se mi víc líbilo to, co jsi navrhoval ty:

>>> getProfile(String name, bool exclude = false, params String[] fieldNames)

Výhrady k řešení nahoře jsem už napsal. Podle mne je lepší zabezpečit, aby metoda přijímala pouze platné argumenty. Pokud někdo zadá i include a exclude, pak těžko říct, jak by se metoda měla zachovat. Zbytečným výjimkám je lepší se vyhnout.

Pokud by někoho zajímalo, jak by se to řešilo pomocí algebraických datových typů, může se podívat tady:

https://gist.github.com/…6cc4c8463f20

 
Nahoru Odpovědět
6.1.2018 13:38
Avatar
hanpari
Člen
Avatar
Odpovídá na gcx11
hanpari:6.1.2018 17:02

Ja tomu rozumim jen s tim nesouhlasim

 
Nahoru Odpovědět
6.1.2018 17:02
Avatar
Petr Šťastný
Tvůrce
Avatar
Odpovídá na hanpari
Petr Šťastný:6.1.2018 21:05

Nebylo by v takovém případě nejlepší vyhodit ArgumentException? Především když výslovně napíšu jak do dokumentace tak do <summary>, že je nutné, aby alespoň jeden z těch nepovinných argumentů byl null.

A ohledně bool, který by určoval, který z parametrů vlastně uživatel zadal do metody, zdá se mi to jako takové zmatečné řešení, teď mě napadá, jestli by nebylo lepší místo boolu enum.

Takže co myslíte? Dva argumenty a vyhazovat ArgumentException, nebo jenom jeden + bool (nebo enum), které identifikuje typ argumentu?

 
Nahoru Odpovědět
6.1.2018 21:05
Avatar
gcx11
Tvůrce
Avatar
Odpovídá na Petr Šťastný
gcx11:6.1.2018 21:29

IMO by bylo nejlepší něco jako:

GetProfileInclude(string name, string endpoint, params string[] includeFields = null)
GetProfileExclude(string name, string endpoint, params string[] excludeFields = null)

Jestli se vnitřní kód hodně podobá, tak až v nich si volat nějaké společné private metody.

Pokud potřebuješ boolean, který přepíná chování metody, tak je to známka toho, že ta metoda dělá dvě různé věci a tudíž by to měly být dvě metody.

Editováno 6.1.2018 21:30
 
Nahoru Odpovědět
6.1.2018 21:29
Avatar
gcx11
Tvůrce
Avatar
Odpovídá na Petr Šťastný
gcx11:6.1.2018 21:34

A ještě lépe toto, ale už mi nešel edit:

GetProfileInclude(string name, string endpoint, string[] includeFields = {})
GetProfileExclude(string name, string endpoint, string[] excludeFields = {})
Editováno 6.1.2018 21:35
 
Nahoru Odpovědět
6.1.2018 21:34
Avatar
gcx11
Tvůrce
Avatar
Odpovídá na Petr Šťastný
gcx11:6.1.2018 21:39

A syntakticky správně v C# je bohužel:

GetProfileInclude(string name, string endpoint, string[] includeFields = null)
GetProfileExclude(string name, string endpoint, string[] excludeFields = null)
 
Nahoru Odpovědět
6.1.2018 21:39
Avatar
hanpari
Člen
Avatar
Odpovídá na Petr Šťastný
hanpari:6.1.2018 21:48

Samozřejmě, že záleží výhradně na tobě. Psát něco do dokumentace a spoléhat na člověka je vždycky riziko.

Proto například v automobilovém průmyslu vyvinuli poka yoke
http://www.ikvalita.cz/tools.php?…

Scott Wlaschin zase tvrdí, že nemáš chybový stav vůbec umožnit, v tomto případě dovolit, aby vstoupili do funkce zároveň include a exclude.

https://fsharpforfunandprofit.com/…presentable/

Ale opravdu záleží jen na tobě.

Co se týče výjimek, já osobně věřím, že je lepší se jim vyhýbat, pokud máš jinou možnost. Je to opravdu jen na tobě. Koneckonců, ty se rozhodni, jestli se mnou souhlasíš nebo ne.

 
Nahoru Odpovědět
6.1.2018 21:48
Avatar
hanpari
Člen
Avatar
Odpovídá na gcx11
hanpari:6.1.2018 21:52

To s tím přepínáním zní správně. Souhlasím, že takhle je to opravdu lepší. Jen mi není jasné, co je ten endpoint? Přehlédl jsem něco?

 
Nahoru Odpovědět
6.1.2018 21:52
Avatar
Petr Šťastný
Tvůrce
Avatar
Odpovídá na hanpari
Petr Šťastný:6.1.2018 22:50

Na začátku jsem psal, že to je wrapper na API, tak asi vycházel z toho :)

 
Nahoru Odpovědět
6.1.2018 22:50
Avatar
Petr Šťastný
Tvůrce
Avatar
 
Nahoru Odpovědět
6.1.2018 22:50
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na hanpari
Jan Vargovský:6.1.2018 23:04

Jasně, vyhodil bych vyjímku. Neznáme kdo to bude pak ve výsledku používat, takže těžko říct. Samozřejmě že mít 2 metody které neumožňují "chybový" stav je lepší, na druhou stranu zase budeš mít více kódu. Designovat signatury metod poslední dobou beru jako nejtěžší část práce, protože je to často dost subjektivní a vždycky najdeš někoho, kdo má úplně jiný styl psaní.

Osobně se mi ty metody nelíbí, protože se to pak blbě hledá a raději bych vymyslel způsob jak to přetížit. Zrovna tohle je dost malý příklad aby to šlo vidět, ale kdybys měl možností vstupů třeba 10, tak tohle dělat tímhle způsobem (přes suffixy), tak by mě asi střelilo :D

 
Nahoru Odpovědět
6.1.2018 23:04
Avatar
hanpari
Člen
Avatar
Odpovídá na Jan Vargovský
hanpari:6.1.2018 23:26

Kromě té výjimky souhlasím i s tebou.
Já osobně bych to řešil jinak, ale to by pak nevypadalo jako C#.
Proto jsem také posílal příklady z F#, který toto umí lépe přes ADT.

Mimochodem, pokud budeš mít deset vstupů, a nějaké podobné podmínky ve smyslu, když platí vstup A nesmí zároveň platit C a D, atd. pak máš velkou šanci, že neošetříš všechno, jak máš a něco ti uteče. A pokud budeš na všechno vyhazovat výjimku, jak to potom bude ošetřovat ten, kdo s tím bude pracovat? Buď vyhodíš něco obecného, pak se stejně všechno sesype a nikdo nebude vědět proč, nebo budeš mít na každý ošetřený případ speciální případ konkrétní výjimku, a pak ten problém přeneseš na někoho jiného, který buď zapomene něco ošetřit nebo to bude řešit bůhvíjak. :)

 
Nahoru Odpovědět
6.1.2018 23:26
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na hanpari
Jan Vargovský:7.1.2018 1:19

To s těmi podmínkami je problém. Poslední dobou ale pracuji s čím dál více API, které byly vygenerovány a tohle z toho vzniklo. Jednoduše pár povinných parametrů a zbytek volitelných, že u těch volitelných musíš dát tu kombinaci, která je platná. Tohle je ale podle mě dost rare případ, protože uvažuju kdy jsem přetěžoval metodu v tom smyslu, že varianta A dělala diametrálně něco jiného než varianta B. Většinou to jede jako pyramida a prostě ty argumenty nabaluješ a až nakonec máš jednu obří metodu, která dělá ten zbytek. Problém u tohodle přístupu je ten, že tam nezahrneš všechny variace, které mohou nastat.

Příklad za všechny co mě napadá je tahle třída - potřebuješ číst ze streamu a pak neuzavírat ten originální stream. Takže ti nezbyde nic jiného než použít tenhle konstruktor. Vždycky to dopadne tak, že koukám do zdrojového kódu co je defaultní hodnota, abych se dostal k tomu parametru, který mě zajímá.

 
Nahoru Odpovědět
7.1.2018 1:19
Avatar
hanpari
Člen
Avatar
Odpovídá na Jan Vargovský
hanpari:7.1.2018 9:20

To je zajímavý příklad, opravdu. Čím víc jsem nad ním uvažoval, tím víc mne napadalo, že by patřil mezi zdejší vtipy. Ve skutečnosti to je přepínač, který by podle logiky, kterou obhajuje Gcx11, měl donutit MS vytvořit dvě třídy: jednu, která zůstává otevřená a druhou, která se uzavře. Pak by se všechno pro tebe zjednodušilo.

 
Nahoru Odpovědět
7.1.2018 9:20
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 21 zpráv z 21.