Programiranje

Pravokotnost Log4j na primeru

Ortogonalnost je koncept, ki se pogosto uporablja za opis modularne in vzdrževalne programske opreme, vendar je lažje razumljiv s pomočjo študije primera. V tem članku Jens Dietrich demistificira pravokotnost in nekatera povezana načela oblikovanja s prikazom njihove uporabe v priljubljeni knjižnici pripomočkov Log4j. Prav tako razpravlja o tem, kako Log4j v nekaj primerih krši pravokotnost, in o možnih rešitvah zastavljenih vprašanj.

Koncept pravokotnosti temelji na grški besedi orthogōnios, kar pomeni "pravokotni". Pogosto se uporablja za izražanje neodvisnosti med različnimi dimenzijami. Ko se predmet premika po x-os v tridimenzionalnem prostoru, njegova y in z koordinate se ne spreminjajo. Sprememba ene dimenzije ne povzroči spremembe druge dimenzije, kar pomeni, da ena dimenzija ne more povzročiti stranskih učinkov za druge.

To pojasnjuje, zakaj se koncept ortogonalnosti pogosto uporablja za opis modularne in vzdržne zasnove programske opreme: razmišljanje o sistemih kot točkah v večdimenzionalnem prostoru (ki jih ustvarjajo neodvisne, pravokotne dimenzije) pomaga razvijalcem programske opreme, da zagotovijo, da naše spremembe enega vidika sistema ne bo imel stranskih učinkov pri drugem.

Zgodi se, da je Log4j, priljubljen odprtokodni dnevniški paket za Javo, dober primer modularne zasnove, ki temelji na ortogonalnosti.

Dimenzije Log4j

Beleženje je le bolj modna različica System.out.println () statement, Log4j pa je pripomoček, ki povzema mehaniko beleženja na platformi Java. Funkcije Log4j med drugim omogočajo razvijalcem naslednje:

  • Prijavite se v različne pripone (ne samo v konzolo, temveč tudi v datoteke, omrežne lokacije, relacijske zbirke podatkov, pripomočke za dnevnike operacijskega sistema in še več)
  • Prijavite se na več ravneh (na primer NAPAKA, OPOZORILO, INFO in RAZPRAVILO)
  • Centralno nadzorujte, koliko informacij se beleži na določeni ravni beleženja
  • Z različnimi postavitvami določite, kako se dogodek beleženja upodablja v niz

Čeprav ima Log4j tudi druge funkcije, se bom osredotočil na te tri razsežnosti njegove funkcionalnosti, da bi raziskal koncept in prednosti pravokotnosti. Upoštevajte, da moja razprava temelji na različici Log4j 1.2.17.

Log4j na JavaWorldu

Pridobite pregled Log4j in se naučite pisati svojega pripomočki Log4j po meri. Želite več vadnic o Javi? Vzemi Glasilo Enterprise Java dostavljeno v vaš nabiralnik.

Ob upoštevanju vrst Log4j kot vidikov

Dodatki, nivo in postavitev so trije vidiki Log4j, ki jih lahko obravnavamo kot neodvisne dimenzije. Uporabljam izraz vidik tukaj kot sinonim za skrb, kar pomeni del zanimanja ali osredotočenosti v programu. V tem primeru je enostavno opredeliti te tri pomisleke na podlagi vprašanj, ki jih posamezna obravnava:

  • Videz: Kam naj se podatki o dogodkih dnevnika pošljejo za prikaz ali shranjevanje?
  • Postavitev: Kako naj bo predstavljen dnevnik?
  • Raven: Katere dnevniške dogodke je treba obdelati?

Zdaj poskusite te vidike skupaj obravnavati v tridimenzionalnem prostoru. Vsaka točka v tem prostoru predstavlja veljavno sistemsko konfiguracijo, kot je prikazano na sliki 1. (Upoštevajte, da ponujam nekoliko poenostavljen pogled na Log4j: Vsaka točka na sliki 1 dejansko ni globalna sistemska konfiguracija, ampak konfiguracija za enega logarja. Sama sekača lahko štejemo za četrto dimenzijo.)

Seznam 1 je tipičen delček kode, ki izvaja Log4j:

Seznam 1. Primer izvedbe Log4j

// nastavitev beleženja! Logger logger = Logger.getLogger ("Foo"); Appender appender = nov ConsoleAppender (); Postavitev postavitve = new org.apache.log4j.TTCCLayout () appender.setLayout (postavitev); logger.addAppender (priloga); logger.setLevel (Level.INFO); // začnite beležiti! logger.warn ("Hello World");

Želim, da pri tej kodi opazite, da je pravokotna: lahko spremenite dodatek, postavitev ali vidik ravni, ne da bi zlomili kodo, ki bi ostala popolnoma funkcionalna. V pravokotni zasnovi je vsaka točka v danem prostoru programa veljavna konfiguracija sistema. Nobena omejitev ne sme omejiti, katere točke v prostoru možnih konfiguracij so veljavne ali ne.

Ortogonalnost je močan koncept, saj nam omogoča, da vzpostavimo sorazmerno preprost miselni model za zapletene primere uporabe. Zlasti se lahko osredotočimo na eno dimenzijo, hkrati pa ignoriramo druge vidike.

Testiranje je pogost in poznan scenarij, pri katerem je ortogonalnost koristna. Funkcionalnost nivojev dnevnika lahko preizkusimo z ustreznim fiksnim parom dodatka in postavitvijo. Ortogonalnost nam zagotavlja, da ne bo presenečenj: ravni dnevnikov bodo delovale na enak način s katero koli kombinacijo dodatka in postavitve. Ne samo, da je to priročno (dela je manj), ampak je tudi potrebno, ker bi bilo nemogoče preizkusiti ravni dnevnikov z vsako znano kombinacijo dodatka in postavitve. To še posebej velja, saj je Log4j, tako kot številna programska orodja in pripomočki, zasnovan tako, da ga lahko razširijo tretje osebe.

Zmanjšanje kompleksnosti, ki ga pravokotnost prinaša programskim programom, je podobno kot pri dimenzijah v geometriji, kjer je zapleteno gibanje točk v n-dimenzionalnem prostoru razčlenjeno na razmeroma preprosto manipulacijo z vektorji. Na tej močni ideji temelji celotno polje linearne algebre.

Oblikovanje in kodiranje za pravokotnost

Če se zdaj sprašujete, kako oblikovati in kodirati pravokotnost svojih programov, potem ste na pravem mestu. Ključna ideja je uporaba abstrakcija. Vsaka dimenzija pravokotnega sistema obravnava določen vidik programa. Takšno dimenzijo ponavadi predstavlja a tip (razred, vmesnik ali naštevanje). Najpogostejša rešitev je uporaba abstraktni tip (vmesnik ali abstraktni razred). Vsak od teh vrst predstavlja dimenzijo, medtem ko primerek tipa predstavlja točke znotraj dane dimenzije. Ker abstraktnih vrst ni mogoče neposredno ustvariti, so potrebni tudi konkretni razredi.

V nekaterih primerih lahko storimo tudi brez njih. Na primer, ne potrebujemo konkretnih razredov, če je tip le markup in ne obdaja vedenja. Potem lahko samo primerimo tip, ki predstavlja dimenzijo, in pogosto vnaprej določimo določen nabor primerov bodisi z uporabo statičnih spremenljivk bodisi z uporabo eksplicitnega tipa oštevilčenja. V seznamu 1 bi to pravilo veljalo za dimenzijo "nivo".

Slika 3. Znotraj dimenzije Level

Splošno pravilo pravokotnosti je, da se izognemo sklicevanjem na določene konkretne vrste, ki predstavljajo druge vidike (dimenzije) programa. To vam omogoča, da napišete generično kodo, ki bo delovala enako za vse možne primerke. Takšna koda se lahko še vedno sklicuje na lastnosti primerkov, če so del vmesnika tipa, ki definira dimenzijo.

Na primer, v Log4j abstraktni tip Postavitev opredeljuje metodo ignoresThrowable (). Ta metoda vrne logično vrednost, ki kaže, ali lahko postavitev upodablja sledi skladov izjem. Ko dodatek uporablja postavitev, bi bilo povsem v redu, če bi nanjo zapisali pogojno kodo ignoresThrowable (). Na primer, lahko dodatek datoteke natisne sledi skladov izjem System.err pri uporabi postavitve, ki ni mogla obvladati izjem.

Na podoben način a Postavitev izvedba se lahko nanaša na določeno Raven pri upodabljanju dogodkov beleženja. Na primer, če je bila raven dnevnika Level.NAPAKA, izvedba postavitve, ki temelji na HTML-ju, lahko sporočilo dnevnika zavije v oznake, ki ga prikažejo v rdeči barvi. Spet je bistvo v tem Level.NAPAKA je definirano z Raven, tip, ki predstavlja dimenzijo.

Vendar se morate izogibati sklicevanjem na posebne izvedbene razrede za druge dimenzije. Če pripeljevalnik uporablja postavitev, tega ni treba vedeti katera vrsta postavitve je. Slika 4 prikazuje dobre in slabe reference.

Več vzorcev in okvirov omogoča lažje izogibanje odvisnostim od vrst izvedbe, vključno z vbrizgavanjem odvisnosti in vzorcem lokatorja storitev.

Krši ortogonalnost

Na splošno je Log4j dober primer uporabe pravokotnosti. Vendar neka koda v Log4j krši to načelo.

Log4j vsebuje pripeti priimek JDBCAppender, ki se uporablja za prijavo v relacijsko bazo podatkov. Glede na razširljivost in priljubljenost relacijske baze podatkov in dejstvo, da je zaradi tega po dnevnih dogodkih enostavno iskati (s poizvedbami SQL), JDBCAppender je pomemben primer uporabe.

JDBCAppender je namenjen odpravljanju težav s prijavo v relacijsko bazo podatkov tako, da dogodke dnevnika pretvori v SQL VSTAVI izjave. To težavo reši z uporabo PatternLayout.

PatternLayout uporablja predloge, da uporabniku omogoči največjo prilagodljivost pri konfiguriranju nizov, ustvarjenih iz dogodkov dnevnika. Predloga je definirana kot niz, spremenljivke, uporabljene v predlogi, pa se ustvarijo iz dnevnika dogodkov med izvajanjem, kot je prikazano v seznamu 2.

Seznam 2. PatternLayout

Vzorec niza = "% p [@% d {dd MMM llllll HH: mm: ss} v% t]% m% n"; Postavitev postavitve = new org.apache.log4j.PatternLayout (vzorec); appender.setLayout (postavitev);

JDBCAppender uporablja a PatternLayout z vzorcem, ki definira SQL VSTAVI izjavo. Za nastavitev uporabljenega stavka SQL lahko uporabimo zlasti naslednjo kodo:

Seznam 3. Stavek SQL za vstavljanje

javna praznina setSql (String s) {sqlStatement = s; if (getLayout () == null) {this.setLayout (novi PatternLayout (s)); } else {((PatternLayout) getLayout ()). setConversionPattern (s); }}

V to kodo je vgrajena implicitna predpostavka, da je postavitev, če je nastavljena pred uporabo setLayout (postavitev) metoda, opredeljena v Videz, je v resnici primer PatternLayout. Kar zadeva pravokotnost, to pomeni, da je v 3D kocki nenadoma veliko točk, ki jih uporabljajo JDBCAppender z postavitvami, ki niso PatternLayout ne predstavljajte več veljavnih sistemskih konfiguracij! To pomeni, da bi vsi poskusi nastavitve niza SQL z drugačno postavitvijo povzročili izjemo med izvajanjem (oddaja razreda).

Slika 5. Prikazovalnik JDBCA, ki krši pravokotnost

Obstaja še en razlog JDBCAppenderOblika je vprašljiva. JDBC ima svoje izjave, pripravljene v mehanizmu predloge. Z uporabo PatternLayoutvendar se motor predloge zaobide. To je žalostno, ker JDBC vnaprej prevede pripravljene izjave, kar vodi do pomembnih izboljšav zmogljivosti. Tega žal ni enostavno rešiti. Očiten pristop bi bil nadzor nad tem, kakšno postavitev lahko uporabimo JDBCAppender s preglasitvijo nastavitve, kot sledi.

Seznam 4. Preglasitev setLayout ()

javna void setLayout (Layout layout) {if (layout instanceOf PatternLayout) {super.setLayout (layout); } else {vrzi novo IllegalArgumentException ("Postavitev ni veljavna"); }}

Žal ima tudi ta pristop težave. Metoda iz seznama 4 vrže izjemo med izvajanjem in aplikacije, ki kličejo to metodo, morda niso pripravljene, da jo ujamejo. Z drugimi besedami, setLayout (postavitev postavitve) metoda ne more zagotoviti, da ne bo vržena nobena izjema med izvajanjem; zato oslabi jamstva (postpogoje), ki jih daje metoda, ki jo preglasi. Če gledamo v smislu predpogojev, setLayout zahteva, da je postavitev primerek PatternLayout, in je torej močnejši predpogojev kot metoda, ki jo preglasi. Kakor koli že, kršili smo temeljno objektno usmerjeno načelo načrtovanja, to je Liskovo nadomestno načelo, ki se uporablja za zaščito dedovanja.

Rešitve

Dejstvo, da ni enostavne rešitve, s katero bi lahko popravili zasnovo JDBCAppender kaže, da je pri delu globlji problem. V tem primeru raven abstrakcije, izbrana pri snovanju osnovnih abstraktnih vrst (zlasti Postavitev) potrebuje natančno uravnavanje. Osrednja metoda, ki jo definira Postavitev je format (dogodek LoggingEvent). Ta metoda vrne niz. Vendar pa je treba pri prijavi v relacijsko bazo podatkov ustvariti niz vrednosti (vrstica) in ne niz.

Ena od možnih rešitev bi bila uporaba bolj dovršene podatkovne strukture kot vrste vračila za obliko. Vendar bi to pomenilo dodatne režijske stroške v situacijah, ko bi dejansko želeli ustvariti niz. Treba bi bilo ustvariti dodatne vmesne predmete in nato zbirati smeti, kar bi ogrozilo zmogljivost dnevnika. Uporaba bolj dovršenega tipa vrnitve bi tudi otežila razumevanje Log4j. Preprostost je zelo zaželen oblikovalski cilj.

Druga možna rešitev bi bila uporaba "večplastne abstrakcije" z uporabo dveh abstraktnih vrst, Videz in Prilagodljiv dodatek ki se razteza Videz. Samo Prilagodljiv dodatek bi nato opredelil metodo setLayout (postavitev postavitve). JDBCAppender bi samo izvedla Videz, medtem ko druge izvedbe dodatkov, kot je ConsoleAppender bi izvedla Prilagodljiv dodatek. Pomanjkljivost tega pristopa je večja zapletenost (npr. Način obdelave konfiguracijskih datotek Log4j) in dejstvo, da se morajo razvijalci informirano odločiti, katero raven abstrakcije uporabiti zgodaj.

V zaključku

V tem članku sem Log4j uporabil kot primer za prikaz načela pravokotnosti oblikovanja in občasnega kompromisa med upoštevanjem načela načrtovanja in doseganjem lastnosti kakovosti sistema, kot je razširljivost. Tudi v primerih, ko je nemogoče doseči popolno pravokotnost, menim, da bi bilo treba kompromis sprejeti zavestno in da bi ga bilo treba dobro dokumentirati (na primer kot tehnični dolg). Glejte razdelek Viri, če želite izvedeti več o konceptih in tehnologijah, obravnavanih v tem članku.

$config[zx-auto] not found$config[zx-overlay] not found