{"id":79465,"date":"2020-04-27T07:42:20","date_gmt":"2020-04-27T05:42:20","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh"},"modified":"2020-04-27T07:42:20","modified_gmt":"2020-04-27T05:42:20","slug":"istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","title":{"rendered":"La verit\u00e0 prima di tutto, o perch\u00e9 \u00e8 necessario progettare un sistema in base alla struttura del database","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Ciao, Habr!<\/p>\n<p>Continuiamo ad esplorare il tema <noindex><a rel=\"nofollow\" href=\"https:\/\/www.piter.com\/collection\/all\/product\/sovremennyy-yazyk-java-lyambda-vyrazheniya-potoki-i-funktsionalnoe-programmirovanie\">Java<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/storage.piter.com\/upload\/contents\/978544611587\/978544611587_X.pdf\">Spring<\/a><\/noindex>, incluso a livello di database. Oggi vi proponiamo di leggere perch\u00e9, nella progettazione di grandi applicazioni, la struttura del database, e non il codice Java, dovrebbe avere un ruolo cruciale, come si fa e quali eccezioni ci sono a questa regola.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex> <br \/>\nIn questo articolo piuttosto tardivo spiegher\u00f2 perch\u00e9 ritengo che nel pratico la modelazione dei dati in un'applicazione debba essere progettata \"partendo dal database\", e non \"partendo dalle capacit\u00e0 di Java\" (o di un altro linguaggio client con cui stai lavorando). Scegliendo il secondo approccio, ti avventuri in un lungo cammino di sofferenza non appena il tuo progetto inizia a crescere.<\/p>\n<p>L'articolo \u00e8 scritto ispirandosi a <noindex><a rel=\"nofollow\" href=\"https:\/\/stackoverflow.com\/questions\/50706556\/kotlin-with-jooq-and-write-table-models-manually-without-code-generation\">una domanda<\/a><\/noindex>, posta su Stack Overflow.<\/p>\n<p>Discussioni interessanti su reddit nelle sezioni <noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/java\/comments\/8p0uj3\/truth_first_or_why_you_should_mostly_implement\/\">\/r\/java<\/a><\/noindex> e <noindex><a rel=\"nofollow\" href=\"https:\/\/www.reddit.com\/r\/programming\/comments\/8p0qle\/truth_first_or_why_you_should_mostly_implement\/\">\/r\/programming<\/a><\/noindex>.<\/p>\n<h4>Generazione di codice<\/h4>\n<p>\nSono rimasto sorpreso nel vedere che esiste una ristretta fascia di utenti che, dopo aver familiarizzato con jOOQ, si lamentano del fatto che, nell'utilizzo di jOOQ, ci si affida seriamente alla generazione del codice sorgente. Nessuno vi impedisce di utilizzare jOOQ come ritenete opportuno e non vi obbliga a utilizzare la generazione del codice. Tuttavia, di default (come descritto nella guida) l'operazione con jOOQ avviene in questo modo: iniziate con lo schema del database (eredidato), eseguite la sua ingegnerizzazione inversa utilizzando il generatore di codice jOOQ, per ottenere un insieme di classi che rappresentano le vostre tabelle, e poi scrivete query tipo-sicure su queste tabelle:<\/p>\n<pre><code class=\"java\">\tfor (Record2 record : DSL.using(configuration)\n\/\/   ^^^^^^^^^^^^^^^^^^^^^^^ Le informazioni sui tipi sono derivate da \n\/\/   il codice generato a cui si riferisce la seguente\n\/\/   condizione SELECT \n \n       .select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)\n\/\/           vvvvv ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^ nomi generati\n       .from(ACTOR)\n       .orderBy(1, 2)) {\n    \/\/ ...\n}<\/code><\/pre>\n<p>\nIl codice viene generato o manualmente al di fuori della build, o manualmente ad ogni build. Ad esempio, una tale rigenerazione pu\u00f2 avvenire immediatamente dopo <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">migrazione del database Flyway, che pu\u00f2 essere eseguita anche manualmente o automaticamente<\/a><\/noindex>.<\/p>\n<h4>Generazione del codice sorgente<\/h4>\n<p>\nCon questi approcci alla generazione del codice \u2013 manuali e automatici \u2013 sono collegate diverse filosofie, vantaggi e svantaggi, che non intendo approfondire in questo articolo. Ma, in generale, l'essenza del codice generato \u00e8 che permette di riprodurre in Java quella \"verit\u00e0\" che consideriamo un dato di fatto, sia all'interno del nostro sistema che all'esterno. In un certo senso, lo stesso fanno i compilatori, che generano bytecode, codice macchina o qualche altro tipo di codice sulla base dei sorgenti \u2013 otteniamo una rappresentazione della nostra \"verit\u00e0\" in un'altra lingua, indipendentemente dalle cause specifiche. <\/p>\n<p>Esistono molti di questi generatori di codice. Ad esempio, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/technotes\/tools\/unix\/xjc.html\">XJC pu\u00f2 generare codice Java basato su file XSD o WSDL<\/a><\/noindex>. Il principio \u00e8 sempre lo stesso:<\/p>\n<ul>\n<li>Esiste una certa verit\u00e0 (interna o esterna) \u2013 ad esempio, una specifica, un modello di dati, ecc.<\/li>\n<li>Abbiamo bisogno di una rappresentazione locale di questa verit\u00e0 nel nostro linguaggio di programmazione.<\/li>\n<\/ul>\n<p>\nIn effetti, generare tale rappresentazione \u00e8 quasi sempre consigliabile per evitare ridondanze.<\/p>\n<h4>Provider di tipi e elaborazione delle annotazioni<\/h4>\n<p>\nNota: un altro approccio pi\u00f9 moderno e specifico per la generazione di codice per jOOQ \u00e8 legato all'uso di provider di tipi, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/fsharp\/tutorials\/type-providers\/\">cos\u00ec come sono implementati in F#<\/a><\/noindex>. In questo caso, il codice viene generato dal compilatore, proprio nella fase di compilazione. In forma di sorgenti, tale codice in linea di principio non esiste. In Java esistono strumenti simili, sebbene non cos\u00ec raffinati: sono i processori di annotazioni, ad esempio, <noindex><a rel=\"nofollow\" href=\"https:\/\/projectlombok.org\">Lombok<\/a><\/noindex>.<\/p>\n<p>In un certo senso, qui avvengono le stesse cose di prima, a eccezione di:<\/p>\n<ul>\n<li>Non vedete il codice generato (forse questa situazione non sembra cos\u00ec sgradevole a qualcuno?)<\/li>\n<li>Devi garantire che i tipi possano essere forniti, cio\u00e8, \"la verit\u00e0\" deve sempre essere disponibile. Questo \u00e8 facile nel caso di Lombok, che annota \"la verit\u00e0\". Un po\u2019 pi\u00f9 complesso con i modelli di database, la cui operativit\u00e0 dipende da una connessione attiva sempre disponibile.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Qual \u00e8 il problema con la generazione di codice?<\/h4>\n<p>\nOltre alla questione su quale sia il modo migliore per avviare la generazione del codice \u2013 manualmente o automaticamente, va anche detto che ci sono persone che ritengono che la generazione del codice non sia affatto necessaria. La giustificazione pi\u00f9 comune che ho incontrato per questo punto di vista \u00e8 che in tal caso risulta difficile configurare la catena di montaggio. \u00c8 vero, \u00e8 davvero difficile. Ci sono costi infrastrutturali aggiuntivi. Se stai appena iniziando a lavorare con un determinato prodotto (sia esso jOOQ, JAXB, Hibernate, ecc.), ci vuole tempo per configurare l'ambiente di lavoro, tempo che preferiresti investire nello studio dell'API stessa per poter poi estrarre valore da essa.<\/p>\n<p>Se i cost di comprendere come funziona il generatore sono troppo elevati, allora si pu\u00f2 dire che l'API non ha fatto un buon lavoro riguardo all'usabilit\u00e0 del generatore di codice (e in seguito si scopre che anche la personalizzazione dell'utente \u00e8 complessa). La facilit\u00e0 d'uso dovrebbe essere la massima priorit\u00e0 per qualsiasi API di questo tipo. Ma questo \u00e8 solo un argomento contro la generazione di codice. Altrimenti, scrivere manualmente una rappresentazione locale della verit\u00e0 interna o esterna \u00e8 del tutto possibile.<\/p>\n<p>Molti diranno che non hanno tempo per occuparsi di tutto ci\u00f2. Hanno scadenze serrate per il loro Super-Prodotto. Poi, in futuro, miglioreremo le linee di assemblaggio, ci sar\u00e0 tempo. Io rispondo loro:<\/p>\n<p><img decoding=\"async\" alt=\"La verit\u00e0 prima di tutto, o perch\u00e9 \u00e8 necessario progettare un sistema in base alla struttura del database\" src=\"\/wp-content\/uploads\/2020\/04\/cd9aca1e0365fa5af28cfc72c201cb8c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/www.flickr.com\/photos\/toddle_email_newsletters\/15596940251\/in\/photostream\/\">Originale<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"http:\/\/audiencestack.com\/static\/blog.html\">Alan O'Rourke, Audience Stack<\/a><\/noindex> <\/p>\n<p><b>Ma in Hibernate \/ JPA \u00e8 cos\u00ec facile scrivere codice \u00abper Java\u00bb. <\/b><\/p>\n<p>Davvero. Per Hibernate e i suoi utenti \u00e8 sia una benedizione che una maledizione. In Hibernate puoi semplicemente scrivere un paio di entit\u00e0, in questo modo:<\/p>\n<pre><code class=\"java\">\t@Entity\nclass Book {\n  @Id\n  int id;\n  String title;\n}<\/code><\/pre>\n<p>\nE quasi tutto \u00e8 pronto. Ora la responsabilit\u00e0 di Hibernate \u00e8 generare le complessit\u00e0 dei \u00abdettagli\u00bb su come esattamente questa entit\u00e0 sar\u00e0 definita nel DDL del tuo \u00abdialetto\u00bb SQL:<\/p>\n<pre><code class=\"sql\">\tCREATE TABLE book (\n  id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,\n  title VARCHAR(50),\n \n  CONSTRAINT pk_book PRIMARY KEY (id)\n);\n \nCREATE INDEX i_book_title ON book (title);<\/code><\/pre>\n<p>\n\u2026 e iniziamo a utilizzare l'applicazione. Davvero una possibilit\u00e0 fantastica per iniziare rapidamente e provare cose diverse.<\/p>\n<p>Tuttavia, permettetemi di correggermi.<\/p>\n<ul>\n<li>Hibernate applicher\u00e0 davvero la definizione di questa chiave primaria denominata?<\/li>\n<li>Hibernate creer\u00e0 un indice su TITLE? \u2013 so per certo che ne avremo bisogno. <\/li>\n<li>A Hibernate far\u00e0 di questo chiave un identificatore nella Identity Specification?<\/li>\n<\/ul>\n<p>\nProbabilmente no. Se stai sviluppando il tuo progetto da zero, \u00e8 sempre comodo semplicemente eliminare il vecchio database e generarne uno nuovo quando aggiungi le annotazioni necessarie. Cos\u00ec, l'entit\u00e0 Book alla fine apparir\u00e0 cos\u00ec: <\/p>\n<pre><code class=\"java\">\t@Entity\n@Table(name = \"book\", indexes = {\n  @Index(name = \"i_book_title\", columnList = \"title\")\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n  String title;\n}\n<\/code><\/pre>\n<p>\nFantastico. Rigenerare. Ancora una volta, in tal caso, sar\u00e0 molto facile all'inizio.<\/p>\n<h4>Ma poi bisogner\u00e0 fare dei pagamenti.<\/h4>\n<p>\nPrima o poi dovr\u00e0 essere messo in produzione. \u00c8 proprio allora che questo modello smetter\u00e0 di funzionare. Perch\u00e9: <\/p>\n<p>In produzione non sar\u00e0 pi\u00f9 possibile, se necessario, scartare il vecchio database e ricominciare da zero. Il vostro database diventer\u00e0 ereditato.<\/p>\n<p>Da ora in poi e per sempre dovrete scrivere <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">script di migrazione DDL, ad esempio utilizzando Flyway<\/a><\/noindex>. E cosa accadr\u00e0 alle vostre entit\u00e0 in questo caso? Potrete adattarle manualmente (e in questo modo raddoppierete il vostro carico di lavoro), oppure direte a Hibernate di rigenerarle per voi (quanto \u00e8 probabile che la generazione corrisponda alle vostre aspettative?) In ogni caso, sarete in svantaggio.<\/p>\n<p>Pertanto, non appena passerete in produzione, avrete bisogno di patch rapidi. E queste devono essere rilasciate in produzione molto rapidamente. Poich\u00e9 non vi siete preparati e non avete organizzato una fluida conveyorizzazione delle vostre migrazioni per la produzione, farete patch di qualsiasi tipo. E poi non riuscirete a fare tutto correttamente in tempo. E incolperete Hibernate, perch\u00e9 \u00e8 sempre colpa di qualcun altro, mai vostra...<\/p>\n<p>Invece, dall'inizio si poteva fare tutto in modo completamente diverso. Ad esempio, mettere ruote rotonde su una bicicletta.<\/p>\n<h4>Inizialmente, il database<\/h4>\n<p>\nLa vera \"verit\u00e0\" nello schema del tuo database e la \"sovranit\u00e0\" su di esso risiedono all'interno del database. Lo schema \u00e8 definito solo nel database stesso e non altrove, e ciascun cliente ha una copia di questo schema, quindi \u00e8 assolutamente sensato imporre il rispetto dello schema e della sua integrit\u00e0 direttamente nel database, dove risiede l'informazione. <br \/>\nQuesta \u00e8 una saggezza antica, infatti trita. Le chiavi primarie e uniche sono importanti. Le chiavi esterne sono utili. Il controllo delle restrizioni \u00e8 positivo. <noindex><a rel=\"nofollow\" href=\"https:\/\/community.oracle.com\/ideas\/13028\">Affermare<\/a><\/noindex> \u2013 \u00e8 positivo. <\/p>\n<p>Inoltre, questo non \u00e8 tutto. Ad esempio, utilizzando Oracle, probabilmente vorrai specificare:<\/p>\n<ul>\n<li>In quale tablespace si trova la tua tabella <\/li>\n<li>Qual \u00e8 il suo valore PCTFREE <\/li>\n<li>Qual \u00e8 la dimensione della cache nella tua sequenza (dietro l'identificatore)<\/li>\n<\/ul>\n<p>\nFor small systems, this might not matter much, but you don't have to wait until you enter the realm of \"big data\" \u2014 you can start benefiting from the optimizations offered by your provider earlier, such as those mentioned above. None of the ORMs I\u2019ve encountered (including jOOQ) provide access to the full set of DDL options you might want to use in your database. ORMs offer some tools that help in writing DDL.<\/p>\n<p>But ultimately, a well-designed schema is hand-written in DDL. Any generated DDL is merely an approximation of it.<\/p>\n<h4>What about the client model?<\/h4>\n<p>\nAs mentioned earlier, on the client side, you will need a copy of your database schema, the client representation. It goes without saying that this client representation must be synchronized with the actual model. What is the best way to achieve this? Using a code generator.<\/p>\n<p>All databases provide their metadata through SQL. Here\u2019s how to retrieve all tables from your database in different SQL dialects:<\/p>\n<pre><code class=\"sql\">\t-- H2, HSQLDB, MySQL, PostgreSQL, SQL Server\nSELECT table_schema, table_name\nFROM information_schema.tables\n \n-- DB2\nSELECT tabschema, tabname\nFROM syscat.tables\n \n-- Oracle\nSELECT owner, table_name\nFROM all_tables\n \n-- SQLite\nSELECT name\nFROM sqlite_master\n \n-- Teradata\nSELECT databasename, tablename\nFROM dbc.tables\n<\/code><\/pre>\n<p>\nQueste query (o simili, a seconda che si debbano considerare anche le viste, le viste materializzate e le funzioni con valore tabellare) vengono anche eseguite tramite la chiamata <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/javase\/10\/docs\/api\/java\/sql\/DatabaseMetaData.html#getTables(java.lang.String,java.lang.String,java.lang.String,java.lang.String%5B%5D)\"><code>DatabaseMetaData.getTables()<\/code><\/a><\/noindex> da JDBC, oppure tramite il modulo meta di jOOQ.<\/p>\n<p>Dai risultati di tali query, \u00e8 relativamente facile generare qualsiasi vista client del modello del tuo database, indipendentemente dalla tecnologia utilizzata nel client.<\/p>\n<ul>\n<li>Se utilizzi JDBC o Spring, puoi creare un insieme di costanti stringa <\/li>\n<li>Se usi JPA, puoi generare tu stesso le entit\u00e0 <\/li>\n<li>Se utilizzi jOOQ, puoi generare il meta-modello di jOOQ<\/li>\n<\/ul>\n<p>\nA seconda di quali funzionalit\u00e0 offre la tua API client (ad es. jOOQ o JPA), il meta-modello generato pu\u00f2 essere veramente ricco e completo. Prendiamo ad esempio le unioni implicite, <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2018\/02\/20\/type-safe-implicit-join-through-path-navigation-in-jooq-3-11\/\">introdotte in jOOQ 3.11<\/a><\/noindex>, che si basa sulle meta informazioni generate sulle relazioni chiave esterne che agiscono tra le tue tabelle.<\/p>\n<p>Ora qualsiasi incremento del tuo database comporter\u00e0 automaticamente l'aggiornamento del codice client. Immagina, ad esempio:<\/p>\n<pre><code class=\"sql\">ALTER TABLE book RENAME COLUMN title TO book_title;<\/code><\/pre>\n<p>\nDavvero vorresti fare questo lavoro due volte? Assolutamente no. Registriamo semplicemente il DDL, lo facciamo passare attraverso la tua pipeline di build e otteniamo l'entit\u00e0 aggiornata:<\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = \"book\", indexes = {\n \n  \/\/ Hai mai pensato a questo?\n  @Index(name = \"i_book_title\", columnList = \"book_title\")\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n \n  @Column(\"book_title\")\n  String bookTitle;\n}<\/code><\/pre>\n<p>\nOppure la classe jOOQ aggiornata. La maggior parte delle modifiche DDL si riflettono anche sulla semantica, non solo sulla sintassi. Pertanto, \u00e8 utile dare un'occhiata al codice compilato per vedere quale codice sar\u00e0 (o potrebbe essere) influenzato dall'incremento del tuo database.<\/p>\n<h4>L'unica verit\u00e0<\/h4>\n<p>\nIndipendentemente dalla tecnologia che utilizzi, c'\u00e8 sempre un modello che rappresenta l'unica fonte di verit\u00e0 per un dato sottosistema \u2013 o, quanto meno, dovremmo cercare di raggiungerlo e evitarci una confusione aziendale in cui la \"verit\u00e0\" \u00e8 ovunque e in nessun posto. Tutto pu\u00f2 essere molto pi\u00f9 semplice. Se stai semplicemente scambiando file XML con un'altra sistema, utilizza semplicemente l'XSD. Dai un'occhiata alla meta-modello INFORMATION_SCHEMA di jOOQ in formato XML:<br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/www.jooq.org\/xsd\/jooq-meta-3.10.0.xsd\">https:\/\/www.jooq.org\/xsd\/jooq-meta-3.10.0.xsd<\/a><\/noindex><\/p>\n<ul>\n<li>L'XSD \u00e8 ben compreso<\/li>\n<li>L'XSD contrassegna molto bene il contenuto XML e consente la validazione in tutti i linguaggi client <\/li>\n<li>L'XSD ha una buona gestione delle versioni e offre una compatibilit\u00e0 retroattiva avanzata <\/li>\n<li>L'XSD pu\u00f2 essere tradotta in codice Java tramite XJC<\/li>\n<\/ul>\n<p>\nL'ultimo punto \u00e8 importante. Quando comunichiamo con un sistema esterno utilizzando messaggi XML, vogliamo assicurarci della validit\u00e0 dei nostri messaggi. Questo \u00e8 molto facile da ottenere grazie a JAXB, XJC e XSD. Sarei completamente folle a pensare che, con un approccio di progettazione \"Java first\", in cui realizziamo i nostri messaggi come oggetti Java, essi possano essere in qualche modo mappati chiaramente su XML e inviati per essere consumati in un altro sistema. XML generato in questo modo sarebbe di scarsa qualit\u00e0, non documentato e difficile da manutenere. Se ci fosse un accordo sul livello di servizio (SLA) per questa interfaccia, lo avremmo gi\u00e0 compromesso.<\/p>\n<p>A dire il vero, \u00e8 proprio quello che succede continuamente con le API JSON, ma questa \u00e8 un'altra storia, la prossima volta mi sfogher\u00f2... <\/p>\n<h4>Database: sono tutti uguali<\/h4>\n<p>\nLavorando con i database, ci si rende conto che essi sono, in linea di principio, simili. Un database possiede i propri dati e deve gestire lo schema. Qualsiasi modifica apportata allo schema deve essere implementata direttamente su DDL per aggiornare l'unica fonte di verit\u00e0.<\/p>\n<p>Quando si verifica un aggiornamento della sorgente, tutti i clienti devono aggiornare le proprie copie del modello. Alcuni clienti possono essere scritti in Java utilizzando jOOQ e Hibernate o JDBC (o tutti e tre). Altri clienti possono essere scritti in Perl (buona fortuna a loro), e altri ancora in C#. Non \u00e8 importante. Il modello principale risiede nel database. I modelli generati tramite ORM sono generalmente di scarsa qualit\u00e0, poco documentati e difficili da sviluppare.<\/p>\n<p>Quindi, non commettete errori. Fin dall'inizio, non fate errori. Lavorate basandovi sul database. Costruite una pipeline di distribuzione che possa essere automatizzata. Includete generatori di codice per copiare comodamente il modello del vostro database e distribuirlo ai clienti. E smettete di preoccuparvi dei generatori di codice. Sono utili. Con loro diventerete pi\u00f9 produttivi. Basta dedicare un po' di tempo alla loro configurazione iniziale \u2013 e poi vi aspettano anni di maggiore produttivit\u00e0, che costituiranno la storia del vostro progetto.<\/p>\n<p>Non ringraziate ancora, dopo.<\/p>\n<h4>Spiegazione<\/h4>\n<p>\nPer chiarezza: Questo articolo non sostiene in alcun modo che l'intero sistema (ovvero, il dominio, la logica aziendale, ecc.) debba essere piegato al modello del tuo database. In questo articolo, parlo del fatto che il codice client che interagisce con il database deve operare basandosi sul modello del database, in modo che la sua struttura non riproduca il modello del database come \"prima classe\". Questa logica si trova solitamente a livello di accesso ai dati sul client.<\/p>\n<p>Nelle architetture a due livelli, che ancora in alcuni casi sono presenti, tale modello di sistema pu\u00f2 essere l'unica opzione possibile. Tuttavia, nella maggior parte dei sistemi, il livello di accesso ai dati mi sembra una \"sottosistema\", che incapsula il modello del database.<\/p>\n<h4>Eccezioni<\/h4>\n<p>\nDa qualsiasi regola ci sono eccezioni, e ho gi\u00e0 detto che l'approccio con la priorit\u00e0 del database e la generazione di codice sorgente pu\u00f2 a volte risultare inadeguato. Ecco un paio di tali eccezioni (probabilmente ce ne saranno altre):<\/p>\n<ul>\n<li>Quando lo schema \u00e8 sconosciuto e deve essere aperto. Ad esempio, sei un fornitore di strumenti che aiutano gli utenti a orientarsi in qualsiasi schema. Uff. Qui niente generazione di codice. Ma comunque, il database prima di tutto.<\/li>\n<li>Quando lo schema deve essere generato al volo per risolvere un certo problema. Questo esempio sembra una versione leggermente sofisticata del pattern. <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">entity attribute value<\/a><\/noindex>, ovvero, non hai realmente uno schema definito. In questo caso, spesso non si pu\u00f2 nemmeno essere certi che un RDBMS sia adatto.<\/li>\n<\/ul>\n<p>\nLe eccezioni sono per loro natura eccezionali. Nella maggior parte dei casi legati all'uso di RDBMS, lo schema \u00e8 gi\u00e0 noto e si trova all'interno dell'RDBMS ed \u00e8 l'unica fonte di 'verit\u00e0', e tutti i clienti devono creare copie derivate. Idealmente, in questo caso, bisognerebbe coinvolgere un generatore di codice.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/piter\/blog\/498816\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443 Java \u0438 Spring, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043a\u043e\u0434 Java, \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u043e\u0437\u0434\u0430\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79466,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79465","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443 Java \u0438 Spring, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043a\u043e\u0434 Java, \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u043e\u0437\u0434\u0430\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e,\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0418\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443 Java \u0438 Spring, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043a\u043e\u0434 Java, \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u043e\u0437\u0434\u0430\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e,\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-04-27T05:42:20+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-04-27T05:42:20+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47La verit\u00e0 prima di tutto, o perch\u00e9 \u00e8 necessario progettare un sistema basandosi sulla struttura del database | ProHoster","description":"Ciao, Habr! Continuiamo a esplorare il tema di Java e Spring, incluso a livello di database. Oggi ti proponiamo di leggere perch\u00e9 nella progettazione di grandi applicazioni la struttura del database, e non il codice Java, dovrebbe avere un'importanza decisiva, come si fa e quali sono le eccezioni a questa regola. In questo articolo piuttosto tardivo ti spiegher\u00f2,","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0418\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0438\u043b\u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043c\u0443 Java \u0438 Spring, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u0442\u043e\u043c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u043a\u043e\u0434 Java, \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u043c\u0435\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0435\u0441\u0442\u044c \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u043e\u0437\u0434\u0430\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044e,","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/istina-prezhde-vsego-ili-pochemu-sistemu-nuzhno-proektirovat-ishodya-iz-ustrojstva-bazy-dannyh","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-04-27T05:42:20+00:00","article:modified_time":"2020-04-27T05:42:20+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79465","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:37:24","updated":"2022-09-29 16:13:15"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/79465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=79465"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/79465\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/79466"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=79465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=79465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=79465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}