Əvvəlcə həqiqət və ya sistemin niyə verilənlər bazası dizaynına əsaslanaraq dizayn edilməsi lazımdır

Hey Habr!

Mövzunu araşdırmağa davam edirik Java и Yaz, o cümlədən verilənlər bazası səviyyəsində. Bu gün sizi böyük proqramlar hazırlayarkən Java kodunun deyil, verilənlər bazası strukturunun niyə həlledici əhəmiyyət kəsb etməli olduğunu, bunun necə edildiyini və bu qaydadan hansı istisnaların olduğunu oxumağa dəvət edirik.

Bu olduqca gec məqalədə mən niyə demək olar ki, bütün hallarda proqramdakı məlumat modelinin “Java imkanlarından” (və ya hansı müştəri dilindən asılı olmayaraq) deyil, “verilənlər bazasından” hazırlanmalı olduğuna inandığımı izah edəcəyəm. ilə işləyir). İkinci yanaşmanı tətbiq etməklə, layihəniz böyüməyə başlayanda özünüzü uzun bir ağrı və əzab yoluna hazırlamış olursunuz.

Məqalə əsasında yazılmışdır bir sual, Stack Overflow-da verilmişdir.

Bölmələrdə reddit haqqında maraqlı müzakirələr /r/java и /r/proqramlaşdırma.

Kod yaratmaq

Nə qədər təəccübləndim ki, jOOQ ilə tanış olan istifadəçilərin belə kiçik bir seqmenti var ki, onlar jOOQ-nun işləmək üçün mənbə kodunun yaradılmasına ciddi şəkildə güvəndiyindən qəzəblənirlər. Heç kim sizə uyğun gördüyünüz kimi jOOQ-dan istifadə etməyə mane olmur və ya kod yaratmaqdan istifadə etməyə məcbur etmir. Lakin jOOQ ilə işləməyin standart (təlimatda təsvir olunduğu kimi) üsulu ondan ibarətdir ki, siz (köhnə) verilənlər bazası sxemi ilə başlayın, jOOQ kod generatorundan istifadə edərək onu tərs mühəndisləşdirərək cədvəllərinizi təmsil edən siniflər toplusunu əldə edin və sonra növü yazın. -bu cədvəllərə təhlükəsiz sorğular:

	for (Record2<String, String> record : DSL.using(configuration)
//   ^^^^^^^^^^^^^^^^^^^^^^^ Информация о типах выведена на 
//   основании сгенерированного кода, на который ссылается приведенное
// ниже условие SELECT 
 
       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
//           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ сгенерированные имена
       .from(ACTOR)
       .orderBy(1, 2)) {
    // ...
}

Kod ya montajdan kənarda, ya da hər bir montajda əl ilə yaradılır. Məsələn, belə bir bərpa dərhal sonra baş verə bilər Flyway verilənlər bazası miqrasiyası, bu da əl ilə və ya avtomatik olaraq edilə bilər.

Mənbə kodunun yaradılması

Kod yaratmaq üçün bu yanaşmalarla əlaqəli müxtəlif fəlsəfələr, üstünlüklər və çatışmazlıqlar var - əl ilə və avtomatik - bu məqalədə ətraflı müzakirə etmək fikrində deyiləm. Lakin, ümumiyyətlə, yaradılan kodun bütün mahiyyəti ondan ibarətdir ki, o, bizə sistem daxilində və ya ondan kənarda təbii olaraq qəbul etdiyimiz “həqiqəti” Java-da təkrar etməyə imkan verir. Müəyyən mənada kompilyatorlar bayt kodunu, maşın kodunu və ya mənbə kodunun hər hansı digər formasını yaradanda bunu edirlər – biz konkret səbəblərdən asılı olmayaraq “həqiqətimizin” başqa dildə təqdimatını alırıq.

Belə kod generatorları çoxdur. Misal üçün, XJC XSD və ya WSDL faylları əsasında Java kodu yarada bilər. Prinsip həmişə eynidir:

  • Bəzi həqiqət var (daxili və ya xarici) - məsələn, spesifikasiya, məlumat modeli və s.
  • Proqramlaşdırma dilimizdə bu həqiqətin yerli təmsilinə ehtiyacımız var.

Üstəlik, artıqlığın qarşısını almaq üçün demək olar ki, həmişə belə bir təqdimat yaratmaq məsləhətdir.

Növ Provayderləri və Annotasiya Emalı

Qeyd: jOOQ üçün kod yaratmaq üçün başqa, daha müasir və spesifik yanaşma tip provayderlərdən istifadə etməkdir, F#-da həyata keçirildiyi üçün. Bu halda, kod əslində kompilyasiya mərhələsində tərtibçi tərəfindən yaradılır. Prinsipcə, belə kod mənbə şəklində mövcud deyil. Java-da oxşar, zərif olmasa da, alətlər var - annotasiya prosessorları, məsələn, Lombok.

Müəyyən mənada, birinci halda olduğu kimi burada da eyni şeylər baş verir, istisna olmaqla:

  • Yaradılan kodu görmürsünüz (bəlkə bu vəziyyət kiməsə daha az iyrənc görünür?)
  • Siz növlərin təmin oluna biləcəyinə əmin olmalısınız, yəni "doğru" həmişə mövcud olmalıdır. “Həqiqəti” şərh edən Lombok vəziyyətində bu asandır. Daimi mövcud canlı əlaqədən asılı olan verilənlər bazası modelləri ilə bu, bir az daha mürəkkəbdir.

Kodun yaradılması ilə bağlı problem nədir?

Kod generasiyasını ən yaxşı şəkildə necə işlətmək barədə çətin suala əlavə olaraq - əl ilə və ya avtomatik olaraq, kodun yaradılmasının ümumiyyətlə lazım olmadığına inanan insanların olduğunu da qeyd etməliyik. Ən tez-tez rastlaşdığım bu nöqteyi-nəzərdən əsaslandırma ondan ibarətdir ki, o zaman tikinti boru kəmərini qurmaq çətindir. Bəli, həqiqətən çətindir. Əlavə infrastruktur xərcləri yaranır. Müəyyən bir məhsula yenicə başlayırsınızsa (istər jOOQ, istər JAXB, istərsə də Hibernate və s.), istehsal mühitinin qurulması API-nin özünü öyrənməyə sərf edəcəyi vaxt tələb edir ki, ondan dəyər əldə edə biləsiniz. .

Generatorun strukturunu anlamaqla bağlı xərclər çox yüksəkdirsə, o zaman, həqiqətən, API kod generatorunun istifadəsində zəif bir iş gördü (və sonra məlum oldu ki, orada istifadəçinin fərdiləşdirilməsi də çətindir). İstənilən belə API üçün istifadəyə yararlılıq ən yüksək prioritet olmalıdır. Ancaq bu, kod yaratmağa qarşı yalnız bir arqumentdir. Əks halda, daxili və ya xarici həqiqətin yerli təqdimatını yazmaq tamamilə əl işidir.

Çoxları deyəcək ki, bütün bunları etməyə vaxtları yoxdur. Onların Super Məhsulu üçün son tarixlər tükənir. Nə vaxtsa montaj konveyerlərini səliqəyə salacağıq, vaxtımız olacaq. Mən onlara cavab verəcəyəm:

Əvvəlcə həqiqət və ya sistemin niyə verilənlər bazası dizaynına əsaslanaraq dizayn edilməsi lazımdır
Orijinal, Alan O'Rourke, Tamaşaçılar yığını

Lakin Hibernate/JPA-da Java kodunu yazmaq çox asandır.

Həqiqətən. Hibernate və onun istifadəçiləri üçün bu, həm xeyir, həm də lənətdir. Hibernate rejimində siz sadəcə olaraq bu kimi bir neçə obyekt yaza bilərsiniz:

	@Entity
class Book {
  @Id
  int id;
  String title;
}

Və demək olar ki, hər şey hazırdır. İndi bu varlığın SQL "dialektinizin" DDL-də dəqiq necə müəyyən ediləcəyi ilə bağlı mürəkkəb "təfərrüatlar" yaratmaq Hazırda Qalmaqdan asılıdır:

	CREATE TABLE book (
  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
  title VARCHAR(50),
 
  CONSTRAINT pk_book PRIMARY KEY (id)
);
 
CREATE INDEX i_book_title ON book (title);

... və tətbiqi işə salın. Tez başlamaq və müxtəlif şeyləri sınamaq üçün həqiqətən gözəl fürsət.

Bununla belə, icazə verin. yalan deyirdim.

  • Hibernate həqiqətən bu adlandırılmış əsas açarın tərifini tətbiq edəcəkmi?
  • Hazırda gözləmə rejimi TITLE-də indeks yaradacaq? - Mən əminəm ki, buna ehtiyacımız olacaq.
  • Hibernate bu açarı İdentifikasiya Spesifikasiyasında dəqiq müəyyənləşdirəcəkmi?

Yəqin ki, yox. Layihənizi sıfırdan inkişaf etdirirsinizsə, lazımi qeydləri əlavə edən kimi köhnə verilənlər bazasını sadəcə atmaq və yenisini yaratmaq həmişə rahatdır. Beləliklə, Kitab varlığı sonda bu formanı alacaq:

	@Entity
@Table(name = "book", indexes = {
  @Index(name = "i_book_title", columnList = "title")
})
class Book {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  int id;
  String title;
}

Sərin. Yenidən canlandırmaq. Yenə də, bu halda başlanğıcda çox asan olacaq.

Ancaq bunun üçün sonra ödəməli olacaqsınız

Gec-tez siz istehsalata getməli olacaqsınız. O zaman bu model fəaliyyətini dayandıracaq. Çünki:

İstehsalda, lazım gələrsə, köhnə verilənlər bazasını atıb sıfırdan başlamaq artıq mümkün olmayacaq. Verilənlər bazanız miras olacaq.

Bundan sonra və əbədi olaraq yazmalı olacaqsınız DDL köçürmə skriptləri, məsələn, Flyway istifadə edərək. Bu halda qurumlarınızla nə baş verəcək? Siz ya onları əl ilə uyğunlaşdıra bilərsiniz (və beləliklə, iş yükünüzü ikiqat artıra bilərsiniz), ya da Hibernate-ə onları sizin üçün bərpa etməsini söyləyə bilərsiniz (gözləntilərinizi qarşılamaq üçün bu şəkildə yaradılanların ehtimalı nə qədərdir?) Hər halda, itirirsiniz.

Beləliklə, istehsala başladıqdan sonra isti yamaqlara ehtiyacınız olacaq. Və onları çox tez istehsala qoymaq lazımdır. İstehsal üçün miqrasiyalarınızın hamar bir boru kəmərini hazırlamadığınız və təşkil etmədiyiniz üçün hər şeyi vəhşicəsinə düzəldirsiniz. Və sonra hər şeyi düzgün etməyə vaxtınız yoxdur. Siz isə Hibernate-i tənqid edirsiniz, çünki bu, həmişə başqasının günahıdır, yalnız siz deyil...

Əvəzində hər şeyi əvvəldən tamam başqa cür etmək olardı. Məsələn, velosipedə yuvarlaq təkərlər qoyun.

Əvvəlcə verilənlər bazası

Verilənlər bazanızın sxemindəki əsl “həqiqət” və onun üzərindəki “suverenlik” verilənlər bazasındadır. Sxem yalnız verilənlər bazasının özündə və başqa heç bir yerdə müəyyən edilir və hər bir müştəridə bu sxemin bir nüsxəsi var, ona görə də sxemə və onun bütövlüyünə riayət olunmasını təmin etmək, bunu birbaşa verilənlər bazasında - məlumatın olduğu yerdə etmək mükəmməl məna kəsb edir. saxlanılır.
Bu köhnə, hətta hiyləgər bir hikmətdir. Əsas və unikal açarlar yaxşıdır. Xarici açarlar yaxşıdır. Məhdudiyyətləri yoxlamaq yaxşıdır. Təsdiqlər - Yaxşı.

Üstəlik, bu, hamısı deyil. Məsələn, Oracle-dan istifadə edərək, yəqin ki, müəyyən etmək istərdiniz:

  • Masanız hansı masa sahəsindədir?
  • Onun PCTFREE dəyəri nədir?
  • Ardıcıllığınızdakı keş ölçüsü nədir (id arxasında)

Bu, kiçik sistemlərdə vacib olmaya bilər, lakin böyük məlumat sferasına keçənə qədər gözləməli deyilsiniz — yuxarıda qeyd olunanlar kimi satıcı tərəfindən təmin edilən yaddaş optimallaşdırmalarından daha tez faydalanmağa başlaya bilərsiniz. Gördüyüm ORM-lərin heç biri (jOOQ daxil olmaqla) verilənlər bazanızda istifadə etmək istəyə biləcəyiniz DDL seçimlərinin tam dəstinə girişi təmin etmir. ORM-lər DDL yazmağınıza kömək edən bəzi alətlər təklif edir.

Ancaq günün sonunda yaxşı dizayn edilmiş bir sxem DDL-də əl ilə yazılmışdır. Hər hansı bir yaradılan DDL onun yalnız təxminisidir.

Bəs müştəri modeli?

Yuxarıda qeyd edildiyi kimi, müştəridə verilənlər bazası sxeminizin surətinə, müştəri görünüşünə ehtiyacınız olacaq. Qeyd etməyə ehtiyac yoxdur ki, bu müştəri görünüşü faktiki modellə sinxronlaşdırılmalıdır. Buna nail olmağın ən yaxşı yolu nədir? Kod generatorundan istifadə.

Bütün verilənlər bazaları meta məlumatlarını SQL vasitəsilə təmin edir. Verilənlər bazanızdan müxtəlif SQL dialektlərində bütün cədvəlləri necə əldə etmək olar:

	-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server
SELECT table_schema, table_name
FROM information_schema.tables
 
-- DB2
SELECT tabschema, tabname
FROM syscat.tables
 
-- Oracle
SELECT owner, table_name
FROM all_tables
 
-- SQLite
SELECT name
FROM sqlite_master
 
-- Teradata
SELECT databasename, tablename
FROM dbc.tables

Bu sorğular (və ya oxşar sorğular, həm də baxışları, maddiləşdirilmiş görünüşləri, cədvəl qiymətli funksiyaları nəzərə almağınızdan asılı olaraq) həm də zəng etməklə yerinə yetirilir. DatabaseMetaData.getTables() JDBC-dən və ya jOOQ meta-modulundan istifadə etməklə.

Bu cür sorğuların nəticələrinə əsasən, müştəridə hansı texnologiyadan istifadə etməyinizdən asılı olmayaraq verilənlər bazası modelinizin istənilən müştəri tərəfində təqdimatını yaratmaq nisbətən asandır.

  • JDBC və ya Spring istifadə edirsinizsə, bir sıra sətir sabitləri yarada bilərsiniz
  • JPA istifadə etsəniz, obyektləri özləri yarada bilərsiniz
  • jOOQ istifadə etsəniz, jOOQ meta-modelini yarada bilərsiniz

Müştəri API (məsələn, jOOQ və ya JPA) tərəfindən nə qədər funksionallıq təklif olunduğundan asılı olaraq, yaradılan meta model həqiqətən zəngin və tam ola bilər. Məsələn, gizli birləşmələrin mümkünlüyünü götürək, jOOQ 3.11-də təqdim edilmişdir, cədvəlləriniz arasında mövcud olan xarici açar əlaqələri haqqında yaradılan meta məlumatlara əsaslanır.

İndi istənilən verilənlər bazası artımı avtomatik olaraq müştəri kodunu yeniləyəcək. Məsələn, təsəvvür edin:

ALTER TABLE book RENAME COLUMN title TO book_title;

Bu işi həqiqətən iki dəfə etmək istərdinizmi? Heç bir halda. Sadəcə olaraq DDL-i yerinə yetirin, onu tikinti boru kəmərinizdən keçirin və yenilənmiş obyekti əldə edin:

@Entity
@Table(name = "book", indexes = {
 
  // Вы об этом задумывались?
  @Index(name = "i_book_title", columnList = "book_title")
})
class Book {
  @Id
  @GeneratedValue(strategy = IDENTITY)
  int id;
 
  @Column("book_title")
  String bookTitle;
}

Və ya yenilənmiş jOOQ sinfi. Əksər DDL dəyişiklikləri yalnız sintaksisə deyil, semantikaya da təsir göstərir. Buna görə də, verilənlər bazası artımınızın hansı kodun təsirlənəcəyini (və ya ola biləcəyini) görmək üçün tərtib edilmiş koda baxmaq faydalı ola bilər.

Tək həqiqət

Hansı texnologiyadan istifadə etməyinizdən asılı olmayaraq, hər zaman hansısa alt sistem üçün həqiqətin yeganə mənbəyi olan bir model var - və ya, ən azı, biz bunun üçün səy göstərməli və “həqiqətin” hər yerdə və heç yerdə olmadığı bu cür müəssisə çaşqınlığından qaçmalıyıq. . Hər şey daha sadə ola bilər. Əgər siz sadəcə olaraq XML fayllarını başqa sistemlə mübadilə edirsinizsə, sadəcə olaraq XSD-dən istifadə edin. XML formasında jOOQ-dan INFORMATION_SCHEMA meta-modelinə baxın:
https://www.jooq.org/xsd/jooq-meta-3.10.0.xsd

  • XSD yaxşı başa düşülür
  • XSD XML məzmununu çox yaxşı tokenləşdirir və bütün müştəri dillərində doğrulamağa imkan verir
  • XSD yaxşı versiyaya malikdir və qabaqcıl geriyə uyğunluğa malikdir
  • XSD XJC istifadə edərək Java koduna tərcümə edilə bilər

Son nöqtə vacibdir. XML mesajlarından istifadə edən xarici sistemlə əlaqə qurarkən, mesajlarımızın etibarlı olduğuna əmin olmaq istəyirik. JAXB, XJC və XSD istifadə edərək buna nail olmaq çox asandır. Mesajlarımızı Java obyektləri kimi hazırladığımız "öncə Java" dizayn yanaşması ilə onların hər hansı bir şəkildə ardıcıl olaraq XML-ə uyğunlaşdırıla və istehlak üçün başqa sistemə göndərilə biləcəyini düşünmək tamamilə dəlilik olardı. Bu şəkildə yaradılan XML çox keyfiyyətsiz, sənədsiz və inkişaf etdirilməsi çətin olacaq. Əgər belə bir interfeys üçün xidmət səviyyəsi müqaviləsi (SLA) olsaydı, biz onu dərhal pozardıq.

Düzünü desəm, JSON API-ləri ilə hər zaman belə olur, amma bu başqa hekayədir, növbəti dəfə mübahisə edəcəyəm...

Verilənlər bazaları: onlar eyni şeydir

Verilənlər bazası ilə işləyərkən, onların hamısının əsas etibarilə oxşar olduğunu başa düşürsən. Baza öz məlumatlarına sahibdir və sxemi idarə etməlidir. Sxemdə edilən hər hansı dəyişiklik birbaşa DDL-də həyata keçirilməlidir ki, tək həqiqət mənbəyi yenilənsin.

Mənbə yeniləməsi baş verdikdə, bütün müştərilər modelin nüsxələrini də yeniləməlidirlər. Bəzi müştərilər jOOQ və Hibernate və ya JDBC (və ya hər ikisi) istifadə edərək Java-da yazıla bilər. Digər müştərilər Perl dilində yazıla bilər (sadəcə onlara uğurlar arzulayırıq), digərləri isə C# ilə yazıla bilər. Fərqi yoxdur. Əsas model verilənlər bazasındadır. ORM-lərdən istifadə etməklə yaradılan modellər adətən keyfiyyətsiz, zəif sənədləşdirilmiş və inkişaf etdirmək çətindir.

Odur ki, səhvlərə yol verməyin. Əvvəldən səhvlərə yol verməyin. Verilənlər bazasından işləyin. Avtomatlaşdırıla bilən yerləşdirmə boru kəməri qurun. Verilənlər bazası modelinizi kopyalamağı və müştərilərə atmağı asanlaşdırmaq üçün kod generatorlarını aktivləşdirin. Və kod generatorları haqqında narahat olmayın. Onlar yaxşıdır. Onlarla daha məhsuldar olacaqsınız. Onları qurmaq üçün sadəcə bir az vaxt sərf etməlisiniz - və sonra sizi illərlə artan məhsuldarlıq gözləyir, bu da layihənizin tarixini təşkil edəcəkdir.

Daha sonra mənə təşəkkür etmə.

Şərhlər

Aydın olmaq üçün: Bu məqalə heç bir şəkildə verilənlər bazası modelinizə uyğunlaşmaq üçün bütün sistemi (yəni, domen, biznes məntiqi və s. və s.) əymək lazım olduğunu müdafiə etmir. Bu yazıda dediyim odur ki, verilənlər bazası ilə qarşılıqlı əlaqədə olan müştəri kodu verilənlər bazası modeli əsasında fəaliyyət göstərməlidir ki, özü də verilənlər bazası modelini “birinci dərəcəli” statusda təkrar yaratmasın. Bu məntiq adətən müştərinizdə məlumat girişi səviyyəsində yerləşir.

Bəzi yerlərdə hələ də qorunub saxlanılan iki səviyyəli arxitekturalarda belə bir sistem modeli yeganə mümkün ola bilər. Bununla belə, əksər sistemlərdə verilənlərə giriş səviyyəsi mənə verilənlər bazası modelini əhatə edən “alt sistem” kimi görünür.

İstisnalar

Hər bir qayda üçün istisnalar var və mən artıq dedim ki, verilənlər bazası-ilk və mənbə kodu yaratmaq yanaşması bəzən uyğunsuz ola bilər. Burada bir neçə belə istisna var (yəqin ki, başqaları da var):

  • Sxem naməlum olduqda və kəşf edilməli olduqda. Məsələn, siz istifadəçilərə hər hansı bir diaqramda naviqasiya etməyə kömək edən alət təminatçısısınız. uh. Burada kod generasiyası yoxdur. Ancaq yenə də verilənlər bazası birinci yerdədir.
  • Bəzi problemi həll etmək üçün tez bir zamanda bir dövrə yaradılmalı olduqda. Bu nümunə nümunənin bir az fantastik versiyası kimi görünür obyekt atributunun dəyəri, yəni sizin həqiqətən dəqiq müəyyən edilmiş sxeminiz yoxdur. Bu vəziyyətdə, RDBMS-nin sizə uyğun olacağına çox vaxt əmin ola bilməzsiniz.

İstisnalar təbiətcə müstəsnadır. RDBMS-nin istifadəsini nəzərdə tutan əksər hallarda sxem əvvəlcədən məlumdur, o RDBMS-də yerləşir və “həqiqətin” yeganə mənbəyidir və bütün müştərilər ondan əldə edilən nüsxələri əldə etməlidirlər. İdeal olaraq, bir kod generatorundan istifadə etməlisiniz.

Mənbə: www.habr.com

Добавить комментарий