Programmēšana

Log4j ortogonalitāte ar piemēru

Ortogonalitāte ir jēdziens, ko bieži lieto, lai aprakstītu modulāru un uzturamu programmatūru, taču to ir vieglāk saprast, izmantojot gadījumu izpēti. Šajā rakstā Jenss Dītrihs demistificē ortogonalitāti un dažus saistītus dizaina principus, demonstrējot to izmantošanu populārajā Log4j lietderības bibliotēkā. Viņš arī apspriež, kā Log4j pāris gadījumos pārkāpj ortogonalitāti, un apspriež iespējamos risinājumus izvirzītajiem jautājumiem.

Ortogonalitātes jēdziena pamatā ir grieķu vārds ortogōnios, kas nozīmē "taisnleņķa". To bieži izmanto, lai izteiktu neatkarību starp dažādām dimensijām. Kad objekts pārvietojas pa x-taksis trīsdimensiju telpā, tā y un z koordinātas nemainās. Izmaiņas vienā dimensijā neizraisa izmaiņas citā dimensijā, kas nozīmē, ka viena dimensija nevar izraisīt blakusparādības citiem.

Tas izskaidro, kāpēc ortogonalitātes jēdziens bieži tiek izmantots, lai aprakstītu modulāru un uzturamu programmatūras dizainu: domājot par sistēmām kā punktiem daudzdimensionālā telpā (ko rada neatkarīgas, ortogonālas dimensijas), programmatūras izstrādātāji palīdz nodrošināt, ka mūsu izmaiņas vienā sistēmas aspektā neradīs blakusparādības citam.

Gadās, ka populārā Java atvērtā pirmkoda mežizstrādes pakete Log4j ir labs moduļu dizaina piemērs, kas balstīts uz ortogonalitāti.

Log4j izmēri

Mežizstrāde ir tikai iecienītākā versija System.out.println () paziņojums, un Log4j ir utilītu pakotne, kas apkopo reģistrēšanas mehāniku Java platformā. Cita starpā Log4j funkcijas ļauj izstrādātājiem rīkoties šādi:

  • Pieteikšanās pie dažādiem papildinātājiem (ne tikai konsolē, bet arī failos, tīkla vietās, relāciju datu bāzēs, operētājsistēmas žurnālu utilītprogrammās un citur)
  • Piesakieties vairākos līmeņos (piemēram, ERROR, WARN, INFO un DEBUG)
  • Centralizēti kontrolējiet, cik daudz informācijas tiek reģistrēts attiecīgajā reģistrēšanas līmenī
  • Izmantojiet dažādus izkārtojumus, lai noteiktu, kā reģistrēšanas notikums tiek atveidots virknē

Lai gan Log4j ir citas funkcijas, es koncentrēšos uz šīm trim funkcionalitātes dimensijām, lai izpētītu ortogonalitātes jēdzienu un priekšrocības. Ņemiet vērā, ka manas diskusijas pamatā ir Log4j versija 1.2.17.

Log4j vietnē JavaWorld

Iegūstiet Log4j pārskats un uzziniet, kā rakstīt pats pielāgoti Log4j papildinātāji. Vai vēlaties vairāk Java apmācību? Dabūt Enterprise Java biļetens piegādāts uz jūsu iesūtni.

Ņemot vērā Log4j tipus kā aspektus

Piederumi, līmenis un izkārtojums ir trīs Log4j aspekti, kurus var uzskatīt par neatkarīgām dimensijām. Es lietoju šo terminu aspekts šeit kā sinonīms vārdam bažas, kas nozīmē daļu no intereses vai uzmanības programmā. Šajā gadījumā ir viegli definēt šīs trīs problēmas, pamatojoties uz jautājumiem, uz kuriem katrs attiecas:

  • Apendents: Kur žurnāla notikuma dati jānosūta rādīšanai vai glabāšanai?
  • Izkārtojums: Kā jāreģistrē žurnāla notikums?
  • Līmenis: Kurus žurnāla notikumus vajadzētu apstrādāt?

Tagad mēģiniet apsvērt šos aspektus kopā trīsdimensiju telpā. Katrs punkts šajā telpā atspoguļo derīgu sistēmas konfigurāciju, kā parādīts 1. attēlā. (Ņemiet vērā, ka es piedāvāju nedaudz vienkāršotu Log4j skatu: katrs 1. attēla punkts faktiski nav globāla sistēmas mēroga konfigurācija, bet gan viena konfigurācija Pašus mežizstrādātājus var uzskatīt par ceturto izmēru.)

1. saraksts ir tipisks koda fragments, kas ievieš Log4j:

Uzskaitīšana 1. Log4j ieviešanas piemērs

// iestatīšanas reģistrēšana! Mežizstrādātāja reģistrētājs = Logger.getLogger ("Foo"); Appender appender = jauns ConsoleAppender (); Izkārtojuma izkārtojums = new org.apache.log4j.TTCCLayout () appender.setLayout (izkārtojums); logger.addAppender (appender); logger.setLevel (Level.INFO); // sāciet mežizstrādi! logger.warn ("Sveika pasaule");

Es vēlos, lai jūs pamanītu šo kodu, ka tas ir ortogonāls: jūs varētu mainīt pielikuma, izkārtojuma vai līmeņa aspektu, nesalaužot kodu, kas paliktu pilnīgi funkcionāls. Ortogonālā dizainā katrs punkts dotajā programmas telpā ir derīga sistēmas konfigurācija. Nav atļauts ierobežot, kuri punkti iespējamo konfigurāciju telpā ir derīgi vai nē.

Ortogonalitāte ir spēcīgs jēdziens, jo tas ļauj mums izveidot salīdzinoši vienkāršu garīgo modeli sarežģītiem lietojuma lietojuma gadījumiem. Jo īpaši mēs varam koncentrēties uz vienu dimensiju, vienlaikus ignorējot citus aspektus.

Testēšana ir izplatīts un pazīstams scenārijs, kur ortogonalitāte ir noderīga. Mēs varam pārbaudīt žurnāla līmeņu funkcionalitāti, izmantojot piemērotu fiksētu apendenta pāri un izkārtojumu. Ortogonalitāte mums nodrošina, ka pārsteigumi nenotiks: žurnāla līmeņi darbosies tāpat kā ar jebkuru pievienotā un izkārtojuma kombināciju. Tas ir ne tikai ērti (ir mazāk darāmā darba), bet arī nepieciešams, jo nebūtu iespējams pārbaudīt žurnāla līmeņus ar katru zināmo papildinātāja un izkārtojuma kombināciju. Tas jo īpaši attiecas uz to, ka Log4j, tāpat kā daudzi programmatūras rīki un utilītas, ir paredzēts paplašināt trešām personām.

Sarežģītības samazinājums, ko ortogonalitāte rada programmatūras programmām, ir līdzīgs tam, kā dimensijas tiek izmantotas ģeometrijā, kur punktu sarežģītā pārvietošanās n-dimensiju telpā tiek sadalīta līdz salīdzinoši vienkāršai vektoru manipulācijai. Uz šīs spēcīgās idejas ir balstīts viss lineārās algebras lauks.

Ortogonalitātes projektēšana un kodēšana

Ja jūs tagad domājat, kā veidot un kodēt ortogonalitāti savās programmās, tad jūs esat īstajā vietā. Galvenā ideja ir izmantot abstrakcija. Katra ortogonālās sistēmas dimensija attiecas uz vienu konkrētu programmas aspektu. Šādu dimensiju parasti pārstāv a tips (klase, saskarne vai uzskaitījums). Visizplatītākais risinājums ir izmantot abstrakts tips (saskarne vai abstrakta klase). Katrs no šiem veidiem apzīmē dimensiju, bet tipa eksemplārs - punkti dotajā dimensijā. Tā kā abstraktos veidus nevar tieši precizēt, nepieciešamas arī konkrētas klases.

Dažos gadījumos mēs varam iztikt bez tiem. Piemēram, mums nav vajadzīgas konkrētas klases, ja tips ir tikai marķējums un neiekļauj uzvedību. Tad mēs varam tikai precizēt tipu, kas pārstāv pašu dimensiju, un bieži vien iepriekš definēt fiksētu gadījumu kopumu, izmantojot statiskos mainīgos vai skaidri izteiktu uzskaites veidu. 1. sarakstā šis noteikums attiecas uz kategoriju “līmenis”.

3. attēls. Dimensijas iekšpusē

Ortogonalitātes vispārējais noteikums ir izvairīties no atsaucēm uz konkrētiem konkrētiem tipiem, kas pārstāv citus programmas aspektus (dimensijas). Tas ļauj rakstīt vispārīgu kodu, kas darbosies vienādi visās iespējamās instancēs. Šāds kods joprojām var atsaukties uz gadījumu īpašībām, ja vien tie ir daļa no tā veida saskarnes, kas nosaka izmēru.

Piemēram, Log4j abstraktā tipa Izkārtojums definē metodi ignorē izmetamo (). Šī metode atgriež Būla vērtību, norādot, vai izkārtojums var atveidot izņēmuma kaudzes pēdas. Kad lietotājs izmanto izkārtojumu, būtu pilnīgi labi rakstīt nosacīto kodu ignorē izmetamo (). Piemēram, failu pievienotājs varētu izdrukāt izņēmuma kaudzes pēdas System.err izmantojot izkārtojumu, kurā nevarēja rīkoties ar izņēmumiem.

Līdzīgā veidā a Izkārtojums īstenošana varētu attiekties uz konkrētu Līmenis atveidojot reģistrēšanas notikumus. Piemēram, ja žurnāla līmenis bija Līmenis. KĻŪDA, HTML izkārtojuma ieviešana varētu ietīt žurnāla ziņojumu tagos, padarot to sarkanu. Atkal būtība ir tāda Līmenis. KĻŪDA ir definēts ar Līmenis, tips, kas apzīmē izmēru.

Tomēr jums vajadzētu izvairīties no atsaucēm uz konkrētām citu kategoriju ieviešanas klasēm. Ja lietotājs izmanto izkārtojumu, tas nav jāzina kāda veida izkārtojuma tas ir. 4. attēls ilustrē labas un sliktas atsauces.

Vairāki modeļi un ietvari atvieglo izvairīšanos no atkarībām no ieviešanas veidiem, ieskaitot atkarības ievadīšanu un pakalpojuma lokatora modeli.

Ortogonalitātes pārkāpšana

Kopumā Log4j ir labs ortogonalitātes izmantošanas piemērs. Tomēr daži Log4j kodi pārkāpj šo principu.

Log4j satur aplikatoru ar nosaukumu JDBCAppender, ko izmanto, lai pieteiktos relāciju datu bāzē. Ņemot vērā relāciju datu bāzes mērogojamību un popularitāti un to, ka tas padara žurnāla notikumus viegli meklējamus (ar SQL vaicājumiem), JDBCAppender ir svarīgs lietošanas gadījums.

JDBCAppender ir paredzēts, lai risinātu problēmu, kas saistīta ar reģistrēšanos relāciju datu bāzē, pārvēršot žurnāla notikumus SQL IELIKT paziņojumi. Tas atrisina šo problēmu, izmantojot a PatternLayout.

PatternLayout izmanto veidni, lai lietotājam nodrošinātu maksimālu elastību, lai konfigurētu virknes, kas ģenerētas no žurnāla notikumiem. Veidne ir definēta kā virkne, un veidnē izmantotie mainīgie tiek instantēti no žurnāla notikumiem izpildlaika laikā, kā parādīts 2. sarakstā.

Sarakstā 2. PatternLayout

Virknes shēma = "% p [@% d {dd MMM gggg HH: mm: ss}% t]% m% n"; Izkārtojuma izkārtojums = new org.apache.log4j.PatternLayout (modelis); appender.setLayout (izkārtojums);

JDBCAppender izmanto a PatternLayout ar modeli, kas nosaka SQL IELIKT paziņojums, apgalvojums. Šādu kodu var izmantot, lai iestatītu izmantoto SQL priekšrakstu:

Sarakstā 3. SQL ievietot priekšrakstu

public void setSql (virkne s) {sqlStatement = s; if (getLayout () == null) {this.setLayout (jauns PatternLayout (s)); } else {((PatternLayout) getLayout ()). setConversionPattern (s); }}

Šajā kodā ir iekļauts netiešs pieņēmums, ka izkārtojums, ja tas ir iestatīts pirms setLayout (izkārtojums) punktā definētā metode Apendents, faktiski ir PatternLayout. Runājot par ortogonalitāti, tas nozīmē, ka pēkšņi daudz punktu 3D kubā tiek izmantoti JDBCAppender ar izkārtojumiem, kas nav PatternLayout vairs nepārstāv derīgas sistēmas konfigurācijas! Tas ir, visi mēģinājumi iestatīt SQL virkni ar citu izkārtojumu radītu izpildlaika (klases cast) izņēmumu.

5. attēls. JDBCAppender pārkāpj ortogonalitāti

Ir vēl viens iemesls JDBCAppenderdizains ir apšaubāms. JDBC ir savi veidnes sagatavoti paziņojumi. Izmantojot PatternLayouttomēr veidņu dzinējs tiek apiets. Tas ir nožēlojami, jo JDBC iepriekš sastāda sagatavotus paziņojumus, kas ievērojami uzlabo veiktspēju. Diemžēl to nav viegli novērst. Acīmredzama pieeja būtu kontrolēt, kādā izkārtojumā var izmantot JDBCAppender ignorējot iestatītāju šādi.

Uzskaitījums 4. Galvenais setLayout ()

public void setLayout (Layout layout) {if (izkārtojums instanceOf PatternLayout) {super.setLayout (izkārtojums); } else {mest jaunu IllegalArgumentException ("Izkārtojums nav derīgs"); }}

Diemžēl arī šai pieejai ir problēmas. 4. saraksta metode rada izpildlaika izņēmumu, un lietojumprogrammas, kas izsauc šo metodi, var nebūt gatavas to uztvert. Citiem vārdiem sakot, setLayout (izkārtojuma izkārtojums) metode nevar garantēt, ka netiek izpildīti izpildlaika izņēmumi; tāpēc tas vājina garantijas (pēcnosacījumus), ko sniedz metode, kuru tā ignorē. Ja mēs to aplūkojam priekšnoteikumu ziņā, setLayout prasa, lai izkārtojums būtu PatternLayout, un tāpēc ir stiprāka priekšnoteikumi, nekā metode, kuru tā ignorē. Katrā ziņā mēs esam pārkāpuši objektorientētā dizaina pamatprincipu, kas ir Liskova aizstāšanas princips, ko izmanto mantojuma saglabāšanai.

Risinājumi

Fakts, ka nav vienkārša risinājuma, kā salabot dizainu JDBCAppender norāda, ka darbā ir kāda dziļāka problēma. Šajā gadījumā abstrakcijas līmenis, kas izvēlēts, izstrādājot abstraktos pamatveidus (īpaši Izkārtojums) ir jāpielāgo. Galvenā metode, ko nosaka Izkārtojums ir formāts (LoggingEvent notikums). Šī metode atgriež virkni. Tomēr, reģistrējoties relāciju datu bāzē, nav jāveido virkne vērtību (rinda), nevis virkne.

Viens no iespējamiem risinājumiem būtu izmantot sarežģītāku datu struktūru kā atgriešanās veidu formātam. Tomēr tas nozīmētu papildu pieskaitāmās izmaksas situācijās, kad jūs patiešām vēlaties izveidot virkni. Būtu jāizveido papildu starpposma objekti un pēc tam jāsavāc atkritumi, apdraudot mežizstrādes ietvara darbību. Izmantojot sarežģītāku atgriešanās veidu, arī Log4j būtu grūtāk saprast. Vienkāršība ir ļoti vēlams dizaina mērķis.

Cits iespējamais risinājums būtu izmantot "slāņveida abstrakciju", izmantojot divus abstraktus veidus, Apendents un CustomizableAppender kas stiepjas Apendents. Tikai CustomizableAppender tad definētu metodi setLayout (izkārtojuma izkārtojums). JDBCAppender tikai īstenotu Apendents, bet citas piedevu realizācijas, piemēram, ConsoleAppender īstenotu CustomizableAppender. Šīs pieejas trūkums ir sarežģītības palielināšanās (piemēram, kā tiek apstrādāti Log4j konfigurācijas faili) un fakts, ka izstrādātājiem ir jāpieņem apzināts lēmums par to, kuru abstrakcijas līmeni izmantot agri.

Noslēgumā

Šajā rakstā es izmantoju Log4j kā piemēru, lai parādītu gan ortogonalitātes dizaina principu, gan neregulāru kompromisu starp dizaina principa ievērošanu un tādas sistēmas kvalitātes atribūta kā mērogojamība sasniegšanu. Pat gadījumos, kad nav iespējams sasniegt pilnīgu ortogonalitāti, es uzskatu, ka kompromisam jābūt apzinātam lēmumam un tam jābūt labi dokumentētam (piemēram, kā tehniskais parāds). Skatiet sadaļu Resursi, lai uzzinātu vairāk par šajā rakstā apskatītajām koncepcijām un tehnoloģijām.

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