{"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 il sistema deve essere progettato tenendo conto della struttura del database","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Ciao, Habr!<\/p>\n<p>Continuiamo a 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\">Primavera<\/a><\/noindex>, inclusi, 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 eccezioni esistono a questa regola.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex> <br \/>\nIn questo articolo piuttosto tardivo spiegher\u00f2 perch\u00e9 credo che praticamente in tutti i casi il modello di dati in un'applicazione debba essere progettato \"partendo dal database\", e non \"partendo dalle possibilit\u00e0 di Java\" (o di un altro linguaggio client con cui lavori). Scegliendo il secondo approccio, entri in un lungo percorso di dolore e sofferenza, non appena il tuo progetto comincia a crescere.<\/p>\n<p>L'articolo \u00e8 scritto in riferimento 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 del codice<\/h4>\n<p>\nSono rimasto molto sorpreso dal fatto che esista un cos\u00ec piccolo strato di utenti che, incontrando jOOQ, si indignano per il fatto che nel lavoro con jOOQ ci si affida seriamente alla generazione del codice sorgente. Nessuno ti impedisce di usare jOOQ come credi sia giusto e non ti costringe a utilizzare la generazione del codice. Ma per impostazione predefinita (come descritto nella guida), il lavoro con jOOQ avviene cos\u00ec: inizi con uno schema del database (ereditato), esegui il reverse engineering con il generatore di codice jOOQ, per ottenere un insieme di classi che rappresentano le tue tabelle e poi scrivi query type-safe per queste tabelle:<\/p>\n<pre><code class=\"java\">\tfor (Record2 record : DSL.using(configuration)\n\/\/   ^^^^^^^^^^^^^^^^^^^^^^^ Le informazioni sui tipi sono state derivate da\n\/\/   codice sorgente 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 seguire subito dopo <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2014\/06\/25\/flyway-and-jooq-for-unbeatable-sql-development-productivity\/\">la 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 tali approcci alla generazione di codice \u2013 manuali e automatici \u2013 sono collegate diverse filosofie, vantaggi e svantaggi, che non intendo discutere in dettaglio in questo articolo. Tuttavia, in generale, la sostanza del codice generato \u00e8 che consente di riprodurre in Java quella \"verit\u00e0\" che accettiamo come un dato di fatto, sia all'interno del nostro sistema che al di fuori di esso. In un certo senso, lo stesso fanno i compilatori, che generano bytecode, codice macchina o qualche altra forma di codice basata su sorgenti \u2013 otteniamo una rappresentazione della nostra \"verit\u00e0\" in un'altra lingua, indipendentemente dalle ragioni 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>\nInoltre, generare tale rappresentazione \u00e8 quasi sempre conveniente \u2013 per evitare ridondanze.<\/p>\n<h4>Fornitori di tipi e elaborazione delle annotazioni<\/h4>\n<p>\nNota: un altro approccio, pi\u00f9 moderno e specifico, alla generazione di codice per jOOQ \u00e8 legato all'uso dei fornitori di tipi, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/fsharp\/tutorials\/type-providers\/\">nella forma in cui sono implementati in F#<\/a><\/noindex>. In tal caso, il codice viene generato dal compilatore, precisamente durante la fase di compilazione. In forma di sorgenti, tale codice non esiste fondamentalmente. In Java esistono strumenti simili, anche se non cos\u00ec eleganti: 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 si verificano le stesse dinamiche che nel primo caso, eccetto per il fatto che:<\/p>\n<ul>\n<li>Non vedi il codice generato (forse a qualcuno questa situazione non sembra cos\u00ec respingente?)<\/li>\n<li>Devi garantire che i tipi possano essere forniti, cio\u00e8, la \"verit\u00e0\" deve sempre essere accessibile. Questo \u00e8 facile nel caso di Lombok, che annota la \"verit\u00e0\". Un po' pi\u00f9 complicato con i modelli di database, il cui funzionamento dipende da una connessione live sempre disponibile.<\/li>\n<\/ul>\n<p><\/p>\n<h4>Qual \u00e8 il problema con la generazione del codice?<\/h4>\n<p>\nOltre alla subdola domanda su come \u00e8 meglio avviare la generazione del codice \u2013 manualmente o automaticamente, \u00e8 necessario menzionare che ci sono persone che credono che la generazione del codice non sia affatto necessaria. La giustificazione di questo punto di vista, che mi \u00e8 stata presentata pi\u00f9 spesso, \u00e8 che diventa difficile configurare la pipeline di compilazione. S\u00ec, \u00e8 davvero difficile. Ci sono costi infrastrutturali aggiuntivi. Se state solo iniziando a lavorare con un determinato prodotto (sia esso jOOQ, JAXB, Hibernate, ecc.), il tempo che dedicate alla configurazione dell'ambiente di lavoro \u00e8 tempo che vorreste trascorrere a studiare l'API stessa, per poi estrarne valore.<\/p>\n<p>Se i costi per capire come funziona il generatore sono troppo alti \u2013 allora, in effetti, l'API non ha lavorato bene sull'usabilit\u00e0 del generatore di codice (e si scopre che anche la personalizzazione da parte dell'utente \u00e8 complessa). La facilit\u00e0 d'uso deve essere la massima priorit\u00e0 per qualsiasi API di questo tipo. Ma questo \u00e8 solo un argomento contro la generazione del codice. Per il resto, \u00e8 assolutamente necessario scrivere completamente a mano la rappresentazione locale della verit\u00e0 interna o esterna.<\/p>\n<p>Molti diranno che non hanno tempo per occuparsi di tutto questo. Hanno scadenze da rispettare per il loro Super-Prodotto. Prima o poi sistemeremo le pipeline di compilazione, ce la faremo. A questo rispondo:<\/p>\n<p><img decoding=\"async\" alt=\"La verit\u00e0 prima di tutto, o perch\u00e9 il sistema deve essere progettato tenendo conto della 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&#8217;Rourke, Audience Stack<\/a><\/noindex> <\/p>\n<p><b>Ma in Hibernate \/ JPA \u00e8 cos\u00ec semplice scrivere codice \"per Java\". <\/b><\/p>\n<p>In effetti. Per Hibernate e i suoi utenti, \u00e8 sia una benedizione sia 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 il compito di Hibernate \u00e8 generare i complessi \"dettagli\" su come esattamente questa entit\u00e0 sar\u00e0 definita nel DDL del tuo \"dialetto\" 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 cominciamo a far girare l'applicazione. \u00c8 davvero una grande possibilit\u00e0 per iniziare a lavorare rapidamente e provare diverse soluzioni.<\/p>\n<p>Tuttavia, permettetemi. Ho esagerato.<\/p>\n<ul>\n<li>Hibernate applicher\u00e0 davvero la definizione di questa chiave primaria nominata?<\/li>\n<li>Hibernate creer\u00e0 un indice su TITLE? \u2013 so per certo che ne avremo bisogno. <\/li>\n<li>Hibernate render\u00e0 sicuramente questa chiave identificativa nella Identity Specification?<\/li>\n<\/ul>\n<p>\nProbabilmente no. Se stai sviluppando il tuo progetto da zero, \u00e8 sempre comodo semplicemente scartare il vecchio database e generarne uno nuovo, appena aggiungi le annotazioni necessarie. Cos\u00ec, l'entit\u00e0 Book alla fine assumer\u00e0 la forma: <\/p>\n<pre><code class=\"java\">\t@Entity\n@Table(name = &quot;book&quot;, indexes = {\n  @Index(name = &quot;i_book_title&quot;, columnList = &quot;title&quot;)\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n  String title;\n}\n<\/code><\/pre>\n<p>\nFantastico. Rigenerare. Ancora, in tal caso sar\u00e0 molto semplice all'inizio.<\/p>\n<h4>Ma in seguito dovrai pagarne il prezzo.<\/h4>\n<p>\nPrima o poi dovrai andare in produzione. \u00c8 proprio allora che un modello simile smetter\u00e0 di funzionare. Perch\u00e9: <\/p>\n<p>In produzione non sar\u00e0 pi\u00f9 possibile scartare il vecchio database e ricominciare tutto da un foglio bianco. Il tuo database diventer\u00e0 ereditato.<\/p>\n<p>D'ora in poi e per sempre dovrai 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 succeder\u00e0, in tal caso, con le tue entit\u00e0? Potrai o adattarle manualmente (e raddoppiare cos\u00ec il carico di lavoro), oppure ordinare a Hibernate di rigenerarle per te (quali sono le probabilit\u00e0 che quelle generate in questo modo corrispondano alle tue aspettative?) Comunque tu perdi.<\/p>\n<p>Quindi, non appena passerai in produzione, avrai bisogno di patch urgenti. E queste devono essere portate in produzione molto rapidamente. Poich\u00e9 non ti sei preparato e non hai organizzato una fluida catena di distribuzione delle tue migrazioni, tutto sar\u00e0 patchato in modo disordinato. Alla fine non riuscirai a fare tutto correttamente. E darai la colpa a Hibernate, perch\u00e9 \u00e8 sempre colpa di qualcun altro, mai tua...<\/p>\n<p>Invece, avresti potuto fare tutto in modo completamente diverso fin dall'inizio. Ad esempio, mettere le ruote tonde sulla bicicletta.<\/p>\n<h4>Prima di tutto il database.<\/h4>\n<p>\nLa vera 'verit\u00e0' nel modello del tuo database e la 'sovranit\u00e0' su di esso risiede all'interno del database stesso. Lo schema \u00e8 definito solo nel database e in nessun altro posto, e ogni cliente ha una copia di questo schema, quindi \u00e8 assolutamente sensato imporre il rispetto dello schema e della sua integrit\u00e0 direttamente nel database \u2013 l\u00e0 dove \u00e8 conservata l'informazione. <br \/>\nQuesto \u00e8 un vecchio e persino trito proverbio. Le chiavi primarie e uniche sono buone. Le chiavi esterne sono buone. La verifica dei vincoli \u00e8 buona. <noindex><a rel=\"nofollow\" href=\"https:\/\/community.oracle.com\/ideas\/13028\">Le affermazioni<\/a><\/noindex> sono buone. <\/p>\n<p>Inoltre, questo non \u00e8 tutto. Ad esempio, utilizzando Oracle, probabilmente vorrete specificare:<\/p>\n<ul>\n<li>In quale tablespace si trova la vostra tabella <\/li>\n<li>Qual \u00e8 il valore di PCTFREE <\/li>\n<li>Qual \u00e8 la dimensione della cache nella vostra sequenza (dopo l'identificatore)<\/li>\n<\/ul>\n<p>\nProbabilmente tutto ci\u00f2 non \u00e8 importante nei piccoli sistemi, ma non \u00e8 necessario attendere il passaggio all'area dei \"big data\" \u2014 si pu\u00f2 iniziare a trarre vantaggio dalle ottimizzazioni fornite dal fornitore molto prima, come quelle menzionate sopra. Nessun ORM che ho visto (incluso jOOQ) offre accesso a tutte le opzioni DDL che si potrebbe desiderare di utilizzare nel proprio database. Gli ORM offrono alcuni strumenti che aiutano a scrivere DDL.<\/p>\n<p>Ma, in fin dei conti, uno schema ben progettato \u00e8 scritto a mano in DDL. Qualsiasi DDL generato \u00e8 solo una sua approssimazione.<\/p>\n<h4>E per quanto riguarda il modello client?<\/h4>\n<p>\nCome accennato sopra, sul client avrete bisogno di una copia dello schema del vostro database, una vista client. \u00c8 superfluo sottolineare che questa vista client deve essere sincronizzata con il modello reale. Qual \u00e8 il modo migliore per farlo? Tramite un generatore di codice.<\/p>\n<p>Tutti i database forniscono la loro metainformazione tramite SQL. Ecco come ottenere da vostro database tutte le tabelle in diversi dialetti SQL:<\/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 se devono essere considerate anche le viste, le viste materializzate, le funzioni con valore tabellare) vengono eseguite anche tramite 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 di metadati jOOQ.<\/p>\n<p>Dai risultati di tali query \u00e8 relativamente facile generare qualsiasi vista client del modello del vostro database, indipendentemente dalla tecnologia utilizzata sul client.<\/p>\n<ul>\n<li>Se utilizzate JDBC o Spring, potete creare un insieme di costanti stringa <\/li>\n<li>Se utilizzate JPA, potete generare voi stessi le entit\u00e0 <\/li>\n<li>Se utilizzate jOOQ, potete generare il metamodelo jOOQ<\/li>\n<\/ul>\n<p>\nA seconda del volume di funzionalit\u00e0 offerto dalla vostra API client (es. jOOQ o JPA), il modello di meta-dati generato pu\u00f2 essere realmente ricco e completo. Prendiamo, ad esempio, la funzione delle join implicite, <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.jooq.org\/2018\/02\/20\/type-safe-implicit-join-through-path-navigation-in-jooq-3-11\/\">introdotta in jOOQ 3.11<\/a><\/noindex>, che si basa sulle informazioni meta generate riguardanti le relazioni delle chiavi esterne esistenti tra le vostre tabelle.<\/p>\n<p>Ora ogni incremento del database porter\u00e0 automaticamente all'aggiornamento del codice client. Immaginate, ad esempio:<\/p>\n<pre><code class=\"sql\">ALTER TABLE book RENAME COLUMN title TO book_title;<\/code><\/pre>\n<p>\nVorreste davvero fare questo lavoro due volte? Assolutamente no. Registriamo semplicemente il DDL, lo facciamo passare attraverso il vostro pipeline di build e otteniamo l'entit\u00e0 aggiornata:<\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = &quot;book&quot;, indexes = {\n \n  \n  @Index(name = &quot;i_book_title&quot;, columnList = &quot;book_title&quot;)\n})\nclass Book {\n  @Id\n  @GeneratedValue(strategy = IDENTITY)\n  int id;\n \n  @Column(&quot;book_title&quot;)\n  String bookTitle;\n}<\/code><\/pre>\n<p>\nOppure la classe jOOQ aggiornata. La maggior parte delle modifiche DDL si rifletta anche sulla semantica, non solo sulla sintassi. Perci\u00f2 \u00e8 utile dare un'occhiata al codice compilato per vedere quale codice sar\u00e0 (o potrebbe essere) interessato dall'incremento del vostro database.<\/p>\n<h4>La verit\u00e0 unica<\/h4>\n<p>\nIndipendentemente dalla tecnologia che usate, c'\u00e8 sempre un modello che \u00e8 l'unica fonte di verit\u00e0 per qualche sottosistema \u2013 o, almeno, dovremmo tendere a questo e evitare una confusione aziendale del tipo dove \"verit\u00e0\" \u00e8 immediatamente ovunque e in nessun posto. Pu\u00f2 essere molto pi\u00f9 semplice. Se semplicemente scambiate file XML con qualche altro sistema, usate semplicemente XSD. Date un'occhiata al modello meta 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>XSD \u00e8 ben comprensibile<\/li>\n<li>XSD etichetta molto bene il contenuto XML e permette di eseguire la validazione in tutti i linguaggi client <\/li>\n<li>XSD \u00e8 ben versionata e ha avanzata retrocompatibilit\u00e0 <\/li>\n<li>XSD pu\u00f2 essere traspormato in codice Java utilizzando XJC<\/li>\n<\/ul>\n<p>\nL'ultimo punto \u00e8 importante. Durante la comunicazione con un sistema esterno tramite messaggi XML, vogliamo assicurarci della validit\u00e0 dei nostri messaggi. Questo \u00e8 molto facile da ottenere grazie a JAXB, XJC e XSD. Sarebbe un completo assurdismo aspettarsi che, con un approccio di progettazione \u2018Java per primo\u2019, in cui creiamo i nostri messaggi come oggetti Java, questi possano essere in qualche modo convertiti in XML e inviati per l'uso in un altro sistema. L'XML generato in questo modo sarebbe di scarsa qualit\u00e0, non documentato e difficile da sviluppare. Se esistesse un accordo sul livello di qualit\u00e0 del servizio (SLA) a riguardo, lo avremmo gi\u00e0 compromesso.<\/p>\n<p>A dire il vero, \u00e8 esattamente quello che accade costantemente con le API JSON, ma questa \u00e8 un'altra storia, ne parler\u00f2 la prossima volta... <\/p>\n<h4>Basi di dati: \u00e8 la stessa cosa<\/h4>\n<p>\nLavorando con i database, si comprende che sono tutti, fondamentalmente, simili. Un database possiede i propri dati e deve gestire lo schema. Qualsiasi modifica apportata allo schema deve essere eseguita direttamente su DDL, affinch\u00e9 venga aggiornato l'unico sorgente di verit\u00e0.<\/p>\n<p>Quando l'aggiornamento della sorgente avviene, 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 (e auguro loro buona fortuna), altri ancora in C#. Non importa. Il modello principale si trova 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. Sin dall'inizio non commettete errori. Lavorate partendo dal database. Costruite una pipeline di distribuzione che possa essere automatizzata. Includete generatori di codice per copiare facilmente il modello del vostro database e integrarlo nei clienti. E smettete di preoccuparvi dei generatori di codice. Sono buoni. Con loro diventerete pi\u00f9 produttivi. \u00c8 solo necessario investire un po' di tempo nella loro configurazione fin dall'inizio \u2013 e poi vi aspettano anni di produttivit\u00e0 aumentata, dai quali si svilupper\u00e0 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 debba adattarsi al modello del tuo database (cio\u00e8, dominio dell'oggetto, logica aziendale, ecc.). In questo articolo parlo del fatto che il codice client, che interagisce con il database, deve funzionare in base al modello del database, in modo che esso stesso non riproduca il modello del database come \"primo classe\". Questa logica si trova di solito a livello di accesso ai dati sul tuo client.<\/p>\n<p>Nelle architetture a due livelli, che in alcune aree sono ancora presenti, un tale modello di sistema pu\u00f2 essere l'unico 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 ogni regola ci sono eccezioni, e ho gi\u00e0 detto che l'approccio con la primariet\u00e0 del database e la generazione del codice sorgente pu\u00f2 talvolta rivelarsi inadeguato. Ecco un paio di tali eccezioni (probabilmente ce ne sono altre):<\/p>\n<ul>\n<li>Quando lo schema \u00e8 sconosciuto e deve essere scoperto. Ad esempio, sei un fornitore di strumenti che aiuta gli utenti a orientarsi in qualsiasi schema. Uff. Qui senza generazione del codice. Ma comunque, il database \u00e8 prima di tutto.<\/li>\n<li>Quando lo schema deve essere generato al volo per risolvere un certo compito. Questo esempio sembra una versione leggermente ricercata del pattern <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Entity%E2%80%93attribute%E2%80%93value_model\">valore attributo entit\u00e0<\/a><\/noindex>, cio\u00e8, non hai realmente uno schema chiaramente definito. In questo caso, spesso non si pu\u00f2 neanche essere certi che un RDBMS sia adatto.<\/li>\n<\/ul>\n<p>\nLe eccezioni per loro natura sono eccezionali. Nella maggior parte dei casi relativi all'utilizzo di un RDBMS, lo schema \u00e8 noto in anticipo, si trova all'interno del RDBMS ed \u00e8 l'unica fonte di \"verit\u00e0\", e tutti i client devono ottenere copie derivate da esso. Idealmente, in questo caso bisognerebbe utilizzare 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 5.0.1.1 - 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\" \/>\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) 5.0.1.1\" \/>\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\" \/>\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 il sistema deve essere progettato partendo dalla struttura del database | ProHoster","description":"Ciao, Habr! Continuiamo a esplorare il tema","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","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","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"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}]}}