Menu

Fluent API vs. named arguments for readability

Fluent APIs are great to make code readable - should I say, at the expense of verbosity? Because verbosity is, actually, one of the positive traits of being fluent. It is very useful in complex and hard to follow scenarios like data transformation (think LINQ), configuration, testing etc., leading the developer to the solution but also documenting what's going on.

One example: I have a LINQ-like method that processes an array. It takes as parameters a criterion for determining duplicates and separate operations for new and repeated entries. It could look like this:

list.DuplicateAwareSelect
(
    r => r.Name.Trim(),
    x => new Entry() { Name = x.Name.Trim(), Date = x.Date },
    (a, b) => { b.Date = a.Date > b.Date ? b.Date : a.Date; }
);

But it isn't obvious what's going on here... The code isn't descriptive at all - and only partially due to the fact that the variable naming scheme stinks. If we make it fluent, the purpose is much clearer:

list.DuplicateAwareSelect()
    .WithKey(r => r.Name.Trim())
    .SelectFirstAppearance(x => new Entry() { Name = x.Name.Trim(), Date = x.Date })
    .ProcessRepeatedAppearance((a, b) => { b.Date = a.Date > b.Date ? b.Date : a.Date; });

But what is the real difference here? In the second example we introduced methods just to describe the parameters from the first example. These parameters had names, though, didn't they, and in this respect the biggest flaw of the first example was that they were invisible. But, we can make them visible using named arguments. Like this:

list.DuplicateAwareSelect
(
    key: r => r.Name.Trim(),
    selectFirstAppearance: x => new Entry() { Name = x.Name.Trim(), Date = x.Date },
    processRepeatedAppearance: (a, b) => { b.Date = a.Date > b.Date ? b.Date : a.Date; }
);

Arguably, this makes the code as readable as the fluent example - aesthetic concerns aside. Of course, fluent can be much more powerful than this and allow more flexibility by providing different methods for different scenarios. But, when describing parameters is the primary concern, named arguments may work just as well.

Naturally, standard rules for code readability also apply, and the first one is naming. If we give descriptive names to arguments, we get something like this:

list.DuplicateAwareSelect
(
    key: sourceRow => sourceRow.Name.Trim(),
    selectFirstAppearance: sourceRow => new Entry() { Name = sourceRow.Name.Trim(), Date = sourceRow.Date },
    processRepeatedAppearance: (sourceRow, previousEntry) => { previousEntry.Date = sourceRow.Date > previousEntry.Date ? previousEntry.Date : sourceRow.Date; }
);

This could be enough for someone familiar with the API to understand the intention.

Artikli

Šifarnik artikala sadrži sledeće podatke:

  • Osnovni podaci - naziv, šifra, stopa pdv, jedinica mere, kratak opis, opis, osnovno pakovanje, proizvođač, glavni dobavljač, tarifni broj itd. Moguće je deaktiviranje artikla bez brisanja, neaktivni artikli više ne mogu da se dodaju u nove dokumente a ostaju u starim.
  • Hijerarhijska kategorizacija, sa kategorijama i potkategorijama. Na svakoj kategoriji može da se definiše šifra i naziv, stopa PDV, zadužene osobe itd. tako da su ti podaci zajednički za sve artikle u datoj kategoriji i njenim potkategorijama.
  • Atributi - korisnici sa odgovarajućim privilegijama mogu da definišu dodatne specifične atribute koje će artikli u određenim kategorijama imati. Na primer, kompjuterski monitori mogu da imaju dijagonalu, aluminijumski profili mogu da imaju dužinu i boju, i slično. Atributi mogu biti numeričkog, tekstualnog i da/ne tipa, i mogu da imaju ili vrednosti koje su predefinisane (tako da se bira jedna od ponuđenih) ili da se slobodno unesu. Moguća je pretraga po njima.
  • Cene
    • Nabavne cene i šifre - artikl ima listu cena kod različitih dobavljača, sa dobavljačevim šiframa i pakovanjima. Takođe postoji datum važenja i moguće je evidentirati istorijat promena. Cene se mogu unositi ili direktno na artikl ili kao poseban dokument (cenovnik dobavljača). Moguća je pretraga artikala po dobavljačevim šiframa.
    • Prodajne cene - definiše se osnovna prodajna cena i prodajne cene ili rabat po kategorijama klijenata ili pojedinačnim klijentima.
    • I jedne i druge cene aplikacija koristi da izračuna prodajnu ili nabavnu cenu kada se artikl doda u dokument određenog tipa (npr. porudžbenicu ili ponudu).
  • Konverzije jedinice mere - odnos između osnovne jedinice mere i jedne ili više alternativnih. Na primer, ako je artikl profil koji se vodi na komad, može da postoji konverzija u metre gde se unese njena dužina. Ovo posle olakšava unos količine u određene dokumente jer je moguć unos i u alternativnim jedinicama pri čemu se količina u osnovnoj jedinici automatski izračunava.
  • Varijacije artikla - jedan artikl može imati neograničen broj varijacija koje predstavljaju isti taj artikl sa drugim atributima (npr. druga boja ili dužina). Varijacije mogu da imaju svoje cene i šifre kod dobavljača, svoje atribute (npr. boju) i svoje konverzije jedinice mere (npr. dužinu). Prilikom unosa stavki u dokumente, bira se osnovni artikl i njegova varijacija, i stanje magacina se vodi u skladu sa time.
  • Revizije (serije/lotovi/batch-evi) - artikl može imati definisane revizije i prilikom unosa stavki dokumenata, pored artikla može da se izabere i revizija. Moguće je definisati aktuelnu reviziju za artikl tako da se ona automatski izabere na dokumentu kada se izabere taj artikl, što je pogodno u proizvodnji artikala kojima se proizvodni proces menja kroz vreme. Stanje magacina se takođe vodi po revizijama, i to je, pored proizvodnje, bitna stvar u sledljivosti u nabavci jer se tačno prati koji batch sirovina je odakle stigao i gde je iskorišćen, a takođe je moguće automatski generisati novu reviziju prilikom prijema materijala.
  • Procesi - u verziji aplikacije koja podržava proizvodnju, moguće je definisati jedan ili više proizvodnih procesa za artikl. Definišu se operacije sa hijerarhijskom strukturom (pod-procesi) na koje mogu da se vezuju artikli sa količinama kao ulaz ili izlaz iz operacije. Kada se kreira proizvodni nalog za određeni artikl, proces se automatski kopira na njega i može da se menja nezavisno od procesa na artiklu, na osnovu procesa i količine koja se proizvodi se automatski kreira specifikacija materijala (koji se zatim nabavlja i kasnije troši) a u proizvodnji se za svaki proizvedeni komad evidentira koje operacije su izvršene. (Za više detalja, pogledati deo vezan za proizvodnju).
  • Prevodi - naziv i opis artikla mogu se zadati u više različitih jezika.
  • Slike - za artikl je moguće odrediti više slika, po jednu za svaku vrstu (pri čemu se i vrste slobodno definišu u aplikaciji), i sa automatski generisanim umanjenim (thumbnail) slikama. Slike se prikazuju na bitnim mestima, u pretrazi artikala ili prilikom izbora artikla u stavkama dokumenata, a takođe mogu da se dodaju u bitne izveštaje za štampu kao što je npr. proizvodni nalog ili plan proizvodnje.
  • Prilozi - moguće vezivanje bilo kakvih fajlova za određeni artikl. Fajlovi se smeštaju centralizovano na server i dostupni su svim korisnicima, zavisno od privilegija.
Subscribe to this RSS feed