8768 sujets

Développement web côté serveur, CMS

Bonjour,

Je poursuis la création de mon CMS maison sous node.js et j'ai une question existentielle. Voici ma problématique : j'ai créé un template pour mes articles, ce dernier s'est trouvé si proche du template pour les topics de forums (là aussi une option que je développe) que je n'ai aucune différence de rendu entre les deux templates (exemple en dur ici vs ici). Et surtout les données de tables sont strictement les mêmes :
CREATE TABLE __article (
  _id                   INT               GENERATED BY DEFAULT AS IDENTITY,
  _name                 VARCHAR(255)      NOT NULL,                         -- titre
  _alternative_headline VARCHAR(255)      NULL,                             -- titre secondaire
  _slug                 VARCHAR(255)      UNIQUE NOT NULL,                  -- slug basé sur le titre
  _content              TEXT              NULL,                             -- contenu
  _created_at           TIMESTAMP         DEFAULT CURRENT_TIMESTAMP,        -- date de création
  _modified_at          TIMESTAMP         NULL,                             -- date de révision
  _type                 VARCHAR(30)       NULL,                             -- article, page, etc...
  _description          VARCHAR(1000)     NULL,                             -- contenu utilisé pour la balise meta description ; pas de limitation car les politiques des moteurs de recherche changent dans le temps.
  _author_id            INT               NOT NULL,                         -- créateur du post (contributeur principal)
  _status               SMALLINT          DEFAULT 1,                        -- brouillon = 0, publié = 1, privé = 2, refusé = 3, corbeille = 9
  _is_readable          BOOLEAN           DEFAULT true,                     -- l'article peut être lu
  _is_commentable       BOOLEAN           DEFAULT false,                    -- les commentaires sont activés
  _is_visible_comments  BOOLEAN           DEFAULT true,                     -- les commentaires sont visibles
  _add                  JSONB             NULL,                             -- permet de stocker des données en vue des microdonnées (clef-valeurs sur une convention schema.org)
  PRIMARY KEY (_id),
  FOREIGN KEY (_author_id) REFERENCES __person(_id) ON DELETE SET NULL,     -- CONSTRAINT __article__person_fkey
  CONSTRAINT lowercase_and_hyphens_only CHECK (_slug ~ '^[a-z0-9-]+$')      -- Minuscules anglaises, chiffres et tirets uniquement
);

D'où ma question du moment : dois-je garder les deux tables séparées ou les fusionner en gardant une colonne pour les départager au moment d'une interrogation SQL sur cette unique table ?

Je suis tenté par la première solution pour son aspect pratique. Ce qui me gêne alors c'est la redondance, en même temps je serais moins limité si je devais étendre l'une ou l'autre table dans une direction spécifique...
Modifié par Olivier C (25 Jun 2024 - 13:23)
Modérateur
Hello,

Perso, je supprimerai l'une des tables et celle qui reste, je la renomme. Sur la table restante (si besoin), j'ajoute une jointure pour catégoriser la row.

schema
Modifié par niuxe (25 Jun 2024 - 14:22)
Modérateur
Bonjour,

Je suis de l'avis contraire. Les articles sont une chose, et les sujets du forum autre chose.

Pour le moment, ils partagent les mêmes attributs, mais tôt ou tard, les articles et les sujets du forum vont évoluer avec le CMS et tu finiras par devoir ajouter certains attributs aux articles spécifiquement ou aux sujets du forum, et tu vas te retrouver avec des colonnes inutiles pour l'un ou l'autre.

Cela va aussi rendre plus complexe les requêtes SQL, car tu devras toujours filtrer les données selon le type d'entité et/ou les jointures ne seront pas les mêmes.

Je n'arrive plus à mettre la main dessus, mais j'avais lu un article qu'il était préférable de créer des tables différentes pour chaque entité, plutôt qu'essayer de toutes les mettre ensemble dans la même table, même si leurs attributs étaient identiques.
Modérateur
Tony Monast a écrit :
Bonjour,

Je suis de l'avis contraire. Les articles sont une chose, et les sujets du forum autre chose.

Pour le moment, ils partagent les mêmes attributs, mais tôt ou tard, les articles et les sujets du forum vont évoluer avec le CMS et tu finiras par devoir ajouter certains attributs aux articles spécifiquement ou aux sujets du forum, et tu vas te retrouver avec des colonnes inutiles pour l'un ou l'autre.

Cela va aussi rendre plus complexe les requêtes SQL, car tu devras toujours filtrer les données selon le type d'entité et/ou les jointures ne seront pas les mêmes.

Je n'arrive plus à mettre la main dessus, mais j'avais lu un article qu'il était préférable de créer des tables différentes pour chaque entité, plutôt qu'essayer de toutes les mettre ensemble dans la même table, même si leurs attributs étaient identiques.


Attention... YAGNI (Obligation de faire un CRUD supplémentaire alors qu'il n'y en pas forcément besoin à l'instant T)

Dans ce cas-là, garder les champs communs dans une table et dans les 2 autres tables enfants, les champs spécifiques à celles-ci. Avec Django, on a la possibilité de créer un model abstrait. Tu définis des champs communs que tu vas pouvoir réutiliser dans les models enfants. Après réflexion, je pense que si je devais faire ce genre de choses (le cms d'Olivier), je serais arrivé à faire ça.

En tout cas, ton idée se défend bien Smiley smile N'oublions pas qu'un ORM avec système de migration aide bien pour ce genre de démarche.

@Olivier : Garde les 2 tables et si en cours de dev, tu vois bien que c'est commun, tu peux dans ce cas réunifier
Modifié par niuxe (26 Jun 2024 - 01:30)
Merci pour vos deux interventions super enrichissantes. Je vais effectivement créer une table par entité et nous verrons bien.

Je marque résolu mais si quelqu'un a une réflexion à rajouter qu'il n'hésite pas.

Bonne journée.
Modifié par Olivier C (26 Jun 2024 - 07:29)
Tony Monast a écrit :
Bonjour,

Je suis de l'avis contraire. Les articles sont une chose, et les sujets du forum autre chose.

Pour le moment, ils partagent les mêmes attributs, mais tôt ou tard, les articles et les sujets du forum vont évoluer avec le CMS et tu finiras par devoir ajouter certains attributs aux articles spécifiquement ou aux sujets du forum, et tu vas te retrouver avec des colonnes inutiles pour l'un ou l'autre.

Cela va aussi rendre plus complexe les requêtes SQL, car tu devras toujours filtrer les données selon le type d'entité et/ou les jointures ne seront pas les mêmes.

Je n'arrive plus à mettre la main dessus, mais j'avais lu un article qu'il était préférable de créer des tables différentes pour chaque entité, plutôt qu'essayer de toutes les mettre ensemble dans la même table, même si leurs attributs étaient identiques.

Bonjour,
Non seulement ceci, mais il y a aussi potentiellement une question de volumétrie. Si l'une des tables fait dans les 1000 lignes(disons article) et l'autre dans les 100 000(disons sujets du forum) ou plus les résultats avec une seule table en ce qui concerne les requêtes dédiées aux articles ne vont pas être très performants.
Salut

Question intéressante et comme le dit tout mes voisins du dessus il y a deux approche possible à toi de faire le choix :

1) Garder les tables séparées
- Tu gagne une structure claire, chaque entité a sa propre table (article/topics) donc strucutre de bdd facile à comprendre/maintenir
- Tu peux appliquer des contraintes spécifique à chaque type de contenue sans affecter l'autre, des règles de validation, etc...
- Si ça les articles ou les topics (en terme de bdd) évolue alors tu es indépendant et c'est plus simple Smiley smile
- Oui, il y a de la redondance, c'est pas beau
- Si tu dois récupe les infos sur les articles ET les topics il se peut que tu fasse des JOIN complexe...

2) Fusionner en une seule table
- Forcement tu réduis la redondance, tu n'a plus de duplication de colonne et tu simplifie la structure de la bdd
- Les requêtes sql deviennent "potentiellement" plus simple car = une seule table Smiley smile
- Peut être plus cohérent ? si les topics/artciel partage les mêmes type de donnée
- Tu perds du coup en flexibilité, si ça se diverge trop tu peux être amener à faire des modifications de structure plus chiante (j'ai eu affaire à ça) genre des colonnes spécifique pour l'un qui seront vide/null pour l'autre (c'est moche)


Tout dépend de ta situation actuelle et des évolutions que tu compte amenée. On parle de "topics" et "d'articles" donc dans l'ensemble ça va.. c'est pas truc hyper complexe.
Modifié par JENCAL (26 Jun 2024 - 17:05)
Modérateur
Bonjour,

niuxe a écrit :


Attention... YAGNI (Obligation de faire un CRUD supplémentaire alors qu'il n'y en pas forcément besoin à l'instant T)


Bien que je respecte ton avis, je ne la partage pas concernant YAGNI dans le contexte ici. Je suggère de bien organiser et séparer les données dans une base de données dès le départ et de bien préparer l'avenir. Je trouve que des articles et un forum sont deux choses complètement différentes et j'ai beaucoup de mal à voir l'intérêt de fusionner les deux dans une même table, même si les colonnes sont similaires. Surtout que ça me semble plus propre et plus simple séparer les deux et demandera moins de travail à long terme. Mélanger les deux entités dans une même table s’apparente, à mes yeux, à introduire volontairement une dette technique dès le départ pour sauver la création d'un CRUD. Mais ça c'est très personnel, comme beaucoup de choses dans ce métier.

YAGNI ok si j'avais proposé de créer une table à l'avance pour le forum au cas où il développerait peut-être un forum un jour. Mais là il est en plein dedans. Il développe un module d'articles et un module de forum. C'est le moment idéal de bien structurer ça pour ne pas à avoir à re-factoriser le tout dans un mois quand il va réaliser que les jointures ne sont pas les mêmes, que des nouvelles colonnes ne sont pas communes, qu'il a besoin de plus de flexibilité pour étendre les fonctionnalités de l'un ou l'autre des modules, qu'il aurait dû isoler chaque module pour simplifier le code, etc...
De toute façon je commence déjà à entrevoir des particularités entre les deux entités, minimes, mais qui vont tout de même influer sur leur colonnes.

Et puis pour l'interrogation des tables je ne trouve pas ça très intuitif de devoir trier à chaque fois (j'appelle mes dix derniers articles, ah non : il faut que je filtre).

Il pourrait bien y avoir une notion d'héritage, mais il me semble qu'imiter l'orienté objet pour le SQL n'est pas une voie à suivre.
Modifié par Olivier C (26 Jun 2024 - 20:08)
Olivier C a écrit :
Il pourrait bien y avoir une notion d'héritage, mais il me semble qu'imiter l'orienté objet pour le SQL n'est pas une voie à suivre.

Hélas !

J’ai exactement le même problème sur plusieurs tables et j’oscille entre 2 tables et une table avec champs distinctifs. Je n’ai pas trouvé LA solution…
PapyJP a écrit :

Hélas !

J’ai exactement le même problème sur plusieurs tables et j’oscille entre 2 tables et une table avec champs distinctifs. Je n’ai pas trouvé LA solution…


normal, il n'y a pas qu'une seul solution. LA solution dépend de ton besoin.

Ta plusieurs possibilité :
Tables séparées avec clé étrangère (Foreign Key)
Table unique avec champ type
Héritage en SQL avec les vues (Views)
Utilisation des types hérités (héritage de table) dans PostgreSQL

etc...
Meilleure solution
JENCAL a écrit :
Utilisation des types hérités (héritage de table) dans PostgreSQL.

Hé, mais c'est génial ! Je suis sous PostgreSQL et je ne savais pas ! Ça va être ça MA solution. Je vais tester ce soir mais a priori ça va être OK. Merci pour tout Jencal.
CREATE TABLE parent (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE child (
    child_specific_column VARCHAR(50)
) INHERITS (parent);

Je vais donc créer une table parente, quelque chose comme "__post", puis garder mes tables "__article" et "__topic" qui du coup deviendront des tables enfants. Ce qui est génial dans l'histoire c'est que quoi que je fasse, que je rassemble des colonnes dans la table parente ou que finalement je subdivise dans les tables enfants, les requêtes SQL d'interrogation des données resteront les mêmes.

Édit : reste sauf quand même la remarque de comar91 sur le rapport performances/volumétrie. Ça vaudrait peut-être le coup, effectivement, que les articles soit très rapidement disponibles. Un forum c'est moins important. À voir. En tous les cas, Jencal, l'approche que tu as suggéré et très intéressante et mérite d'être considérée.
Modifié par Olivier C (27 Jun 2024 - 12:56)
Au besoin tu as aussi une colonne système TABLEOID qui te permet de voir de quel table provient ta data quand tu es dans un systeme d'héritage ! et du coup tu peux faire une jointue avec pg_class pour voir le "nom" de la table et non l'id de tableoid

EDIT :

Tu dis "les requêtes SQL d'interrogation des données resteront les mêmes.", je rebondis, attention l'héritage ne fonctionne pas avec INSERT
Modifié par JENCAL (27 Jun 2024 - 15:52)
Modérateur
Bonjour Olivier,

Olivier C a écrit :

Édit : reste sauf quand même la remarque de comar91 sur le rapport performances/volumétrie. Ça vaudrait peut-être le coup, effectivement, que les articles soit très rapidement disponibles. Un forum c'est moins important. À voir. En tous les cas, Jencal, l'approche que tu as suggéré et très intéressante et mérite d'être considérée.


C'est effectivement à considérer. Ça peut être un bon argument pour garder les deux isolés, mais pour rester objectif, avec une bonne optimisation des requêtes SQL, des indexes et un système de cache, je ne crois pas que ça peut devenir problématique que les articles et les sujets se retrouvent dans la même table. D'ailleurs, en 2024, est-ce que c'est encore populaire les forums, au point de vouloir en développer un à partir de zéro? Je dis ça, je dis rien hein!

Jencal a écrit :

Tu dis "les requêtes SQL d'interrogation des données resteront les mêmes.", je rebondis, attention l'héritage ne fonctionne pas avec INSERT


Je n'ai jamais utilisé l'héritage et PostgreSQL. J'en comprends qu'il devra faire un INSERT dans la table Parent et un INSERT dans la table Enfant?

Ça me semble plus simple et moins abstrait de faire seulement deux tables, une pour les articles et l'autre pour les sujets du forum. Ce n'est pas une mauvaise pratique d'avoir deux tables avec les mêmes colonnes, surtout que les articles n'ont rien à avoir avec les sujets d'un forum.

Quand même intéressant l'héritage. Je vais me documenter là-dessus, car ça m'intrigue comment le lien se fait entre les deux tables, notamment lors d'une insertion.
Modifié par Tony Monast (27 Jun 2024 - 17:16)
Modérateur
Bonjour JENCAL,

JENCAL a écrit :

Tu dis "les requêtes SQL d'interrogation des données resteront les mêmes.", je rebondis, attention l'héritage ne fonctionne pas avec INSERT


Es-tu certain de ça? J'essaye de me documenter là-dessus, mais ça m'apparaîtrait logique qu'on puisse insérer dans la table enfant les données de toutes les colonnes qu'elle possède en plus de celles dont elle a héritée de la table parente. Ou bien j'ai mal interprété ta mise en garde.

Voici l'article que j'ai trouvé : https://docs.postgresql.fr/16/ddl-inherit.html Le seul exemple d'INSERT qui est donné et qui ne fonctionne pas, c'est parce que la requête tente d'insérer dans la table parente une donnée dans une colonne qui n'existe que dans la table enfant.
Modifié par Tony Monast (27 Jun 2024 - 17:25)
Tony Monast a écrit :
Voici l'article que j'ai trouvé : https://docs.postgresql.fr/16/ddl-inherit.html Le seul exemple d'INSERT qui est donné et qui ne fonctionne pas, c'est parce que la requête tente d'insérer dans la table parente une donnée dans une colonne qui n'existe que dans la table enfant.

@Jencal et @Tony Monast : Entre temps j'ai lu la documentation à se sujet (et j'ai aussi vu passer tableoid). Et selon la documentation tout fonctionne correctement avec SELECT, UPDATE et DELETE.

Du coup, pour INSERT, une insertion sur une table fille incrémente bien la table parente. Exemple :
CREATE TABLE parent (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE child1 (
    child1_specific_column VARCHAR(50)
) INHERITS (parent);

CREATE TABLE child2 (
    child2_specific_column INTEGER
) INHERITS (parent);

-- Insertion de données dans les tables filles
INSERT INTO child1 (name, child1_specific_column) VALUES ('Alice', 'Data1');
INSERT INTO child2 (name, child2_specific_column) VALUES ('Bob', 123);

Modifié par Olivier C (27 Jun 2024 - 21:07)
Tony Monast a écrit :
D'ailleurs, en 2024, est-ce que c'est encore populaire les forums, au point de vouloir en développer un à partir de zéro? Je dis ça, je dis rien hein!

Tout à fait. En même temps qui serait assez fou, en 2024, pour réinventer la roue en codant de zéro un CMS quand on sait ce qui existe sur le marché ? Smiley biggol

Pour le forum, étant donné que mon système de rédaction d'articles, leur commentaires et leur tags associés sont déjà fonctionnels, étendre la même chose pour créer un système de topics n'est rien. C'est quasiment du copier/coller. Un truc simple bien sûr : l'organisation des forums sera basés sur les tags, comme pour les articles.