[{"data":1,"prerenderedAt":1236},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Fbusiness\u002Frepositories":189},[4],{"title":5,"path":6,"stem":7,"children":8,"page":52},"Fr","\u002Ffr","fr",[9],{"title":10,"path":11,"stem":12,"children":13},"Qu'est-ce que Fougere","\u002Ffr\u002Fdocs","fr\u002Fdocs\u002Findex",[14,15,19,23,27,31,53,78,123,148],{"title":10,"path":11,"stem":12},{"title":16,"path":17,"stem":18},"Démarrer","\u002Ffr\u002Fdocs\u002Fgetting-started","fr\u002Fdocs\u002F01.getting-started",{"title":20,"path":21,"stem":22},"Une app que vous avez déjà","\u002Ffr\u002Fdocs\u002Fexisting-app","fr\u002Fdocs\u002F02.existing-app",{"title":24,"path":25,"stem":26},"Apportez votre schéma","\u002Ffr\u002Fdocs\u002Fbring-your-schema","fr\u002Fdocs\u002F03.bring-your-schema",{"title":28,"path":29,"stem":30},"La CLI","\u002Ffr\u002Fdocs\u002Fcli","fr\u002Fdocs\u002F04.cli",{"title":32,"path":33,"stem":34,"children":35,"page":52},"Concepts","\u002Ffr\u002Fdocs\u002Fconcepts","fr\u002Fdocs\u002F2.concepts",[36,40,44,48],{"title":37,"path":38,"stem":39},"Philosophie","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fphilosophy","fr\u002Fdocs\u002F2.concepts\u002F1.philosophy",{"title":41,"path":42,"stem":43},"La Frond","\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond","fr\u002Fdocs\u002F2.concepts\u002F2.frond",{"title":45,"path":46,"stem":47},"Le chemin le plus court","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path","fr\u002Fdocs\u002F2.concepts\u002F3.shortest-path",{"title":49,"path":50,"stem":51},"Le socle","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fthe-base","fr\u002Fdocs\u002F2.concepts\u002F4.the-base",false,{"title":54,"path":55,"stem":56,"children":57,"page":52},"Schéma","\u002Ffr\u002Fdocs\u002Fschema","fr\u002Fdocs\u002F3.schema",[58,62,66,70,74],{"title":59,"path":60,"stem":61},"Entités","\u002Ffr\u002Fdocs\u002Fschema\u002Fentities","fr\u002Fdocs\u002F3.schema\u002F1.entities",{"title":63,"path":64,"stem":65},"Vues","\u002Ffr\u002Fdocs\u002Fschema\u002Fviews","fr\u002Fdocs\u002F3.schema\u002F2.views",{"title":67,"path":68,"stem":69},"La carte d'identité","\u002Ffr\u002Fdocs\u002Fschema\u002Fcard","fr\u002Fdocs\u002F3.schema\u002F3.card",{"title":71,"path":72,"stem":73},"Standard Schema","\u002Ffr\u002Fdocs\u002Fschema\u002Fstandard-schema","fr\u002Fdocs\u002F3.schema\u002F4.standard-schema",{"title":75,"path":76,"stem":77},"Comment un schéma bouge","\u002Ffr\u002Fdocs\u002Fschema\u002Fevolution","fr\u002Fdocs\u002F3.schema\u002F5.evolution",{"title":79,"path":80,"stem":81,"children":82,"page":52},"Métier","\u002Ffr\u002Fdocs\u002Fbusiness","fr\u002Fdocs\u002F4.business",[83,87,91,95,99,103,107,111,115,119],{"title":84,"path":85,"stem":86},"Handlers","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers","fr\u002Fdocs\u002F4.business\u002F1.handlers",{"title":88,"path":89,"stem":90},"Les ports","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fports","fr\u002Fdocs\u002F4.business\u002F10.ports",{"title":92,"path":93,"stem":94},"Presenters","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fpresenters","fr\u002Fdocs\u002F4.business\u002F2.presenters",{"title":96,"path":97,"stem":98},"Collectors","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors","fr\u002Fdocs\u002F4.business\u002F3.collectors",{"title":100,"path":101,"stem":102},"Erreurs","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ferrors","fr\u002Fdocs\u002F4.business\u002F4.errors",{"title":104,"path":105,"stem":106},"Seeds","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fseeds","fr\u002Fdocs\u002F4.business\u002F5.seeds",{"title":108,"path":109,"stem":110},"Les faits","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ffacts","fr\u002Fdocs\u002F4.business\u002F6.facts",{"title":112,"path":113,"stem":114},"Le port Storage","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fstorage","fr\u002Fdocs\u002F4.business\u002F7.storage",{"title":116,"path":117,"stem":118},"Des écritures qui tiennent ou tombent ensemble","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ftogether","fr\u002Fdocs\u002F4.business\u002F8.together",{"title":120,"path":121,"stem":122},"Les repositories","\u002Ffr\u002Fdocs\u002Fbusiness\u002Frepositories","fr\u002Fdocs\u002F4.business\u002F9.repositories",{"title":124,"path":125,"stem":126,"children":127,"page":52},"Client","\u002Ffr\u002Fdocs\u002Fclient","fr\u002Fdocs\u002F5.client",[128,132,136,140,144],{"title":129,"path":130,"stem":131},"Queries & commands","\u002Ffr\u002Fdocs\u002Fclient\u002Fqueries-commands","fr\u002Fdocs\u002F5.client\u002F1.queries-commands",{"title":133,"path":134,"stem":135},"Formulaires","\u002Ffr\u002Fdocs\u002Fclient\u002Fforms","fr\u002Fdocs\u002F5.client\u002F2.forms",{"title":137,"path":138,"stem":139},"Session","\u002Ffr\u002Fdocs\u002Fclient\u002Fsession","fr\u002Fdocs\u002F5.client\u002F3.session",{"title":141,"path":142,"stem":143},"invoke","\u002Ffr\u002Fdocs\u002Fclient\u002Finvoke","fr\u002Fdocs\u002F5.client\u002F4.invoke",{"title":145,"path":146,"stem":147},"Back-office","\u002Ffr\u002Fdocs\u002Fclient\u002Fadmin","fr\u002Fdocs\u002F5.client\u002F5.admin",{"title":149,"path":150,"stem":151,"children":152,"page":52},"Infrastructure","\u002Ffr\u002Fdocs\u002Finfra","fr\u002Fdocs\u002F6.infra",[153,157,161,165,169,173,177,181,185],{"title":154,"path":155,"stem":156},"Le gradient","\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient","fr\u002Fdocs\u002F6.infra\u002F1.gradient",{"title":158,"path":159,"stem":160},"Surfaces — REST & GraphQL","\u002Ffr\u002Fdocs\u002Finfra\u002Fsurfaces","fr\u002Fdocs\u002F6.infra\u002F2.surfaces",{"title":162,"path":163,"stem":164},"Déploiement","\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment","fr\u002Fdocs\u002F6.infra\u002F3.deployment",{"title":166,"path":167,"stem":168},"Hôtes","\u002Ffr\u002Fdocs\u002Finfra\u002Fhosts","fr\u002Fdocs\u002F6.infra\u002F4.hosts",{"title":170,"path":171,"stem":172},"Les sources","\u002Ffr\u002Fdocs\u002Finfra\u002Fsources","fr\u002Fdocs\u002F6.infra\u002F5.sources",{"title":174,"path":175,"stem":176},"Le cycle de vie","\u002Ffr\u002Fdocs\u002Finfra\u002Flifecycle","fr\u002Fdocs\u002F6.infra\u002F6.lifecycle",{"title":178,"path":179,"stem":180},"L'identité entre Fronds","\u002Ffr\u002Fdocs\u002Finfra\u002Fidentity","fr\u002Fdocs\u002F6.infra\u002F7.identity",{"title":182,"path":183,"stem":184},"Observabilité","\u002Ffr\u002Fdocs\u002Finfra\u002Fobservability","fr\u002Fdocs\u002F6.infra\u002F8.observability",{"title":186,"path":187,"stem":188},"Tests","\u002Ffr\u002Fdocs\u002Finfra\u002Ftesting","fr\u002Fdocs\u002F6.infra\u002F9.testing",{"id":190,"title":120,"body":191,"description":1231,"extension":1232,"meta":1233,"navigation":409,"path":121,"seo":1234,"stem":122,"__hash__":1235},"docs_fr\u002Ffr\u002Fdocs\u002F4.business\u002F9.repositories.md",{"type":192,"value":193,"toc":1223},"minimark",[194,198,209,220,356,359,485,495,500,511,522,525,551,568,593,597,604,612,615,628,632,639,646,924,927,933,936,973,978,984,1183,1190,1196,1200,1211,1214,1219],[195,196,120],"h1",{"id":197},"les-repositories",[199,200,201,208],"p",{},[202,203,204],"a",{"href":113},[205,206,207],"code",{},"Storage"," est un port : des gestes génériques, aucun parfum de\ndomaine. « Les relevés bruyants » n'en est pas un, donc cette requête finit épelée sur\nplace, au milieu du calcul qu'elle alimente. Une requête sans domicile squatte la réponse.",[199,210,211,214,215,219],{},[205,212,213],{},"Repository(Entity)"," lui en donne un, et ",[216,217,218],"strong",{},"est"," le stockage de cette entité : tous les\ngestes du port, plus ce que vous nommez par-dessus.",[221,222,227],"pre",{"className":223,"code":224,"language":225,"meta":226,"style":226},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","\u002F\u002F repositories\u002FReadingRepository.ts\nexport default class ReadingRepository extends Repository(Reading) {\n  loud(): Promise\u003CReading[]> {\n    return this.findAllBy({ loud: true });\n  }\n}\n","ts","",[205,228,229,238,271,303,344,350],{"__ignoreMap":226},[230,231,234],"span",{"class":232,"line":233},"line",1,[230,235,237],{"class":236},"sutJx","\u002F\u002F repositories\u002FReadingRepository.ts\n",[230,239,241,245,248,252,256,259,263,267],{"class":232,"line":240},2,[230,242,244],{"class":243},"sVHd0","export",[230,246,247],{"class":243}," default",[230,249,251],{"class":250},"sbsja"," class",[230,253,255],{"class":254},"sbgvK"," ReadingRepository",[230,257,258],{"class":250}," extends",[230,260,262],{"class":261},"sGLFI"," Repository",[230,264,266],{"class":265},"su5hD","(Reading) ",[230,268,270],{"class":269},"sP7_E","{\n",[230,272,274,278,281,285,288,291,294,297,300],{"class":232,"line":273},3,[230,275,277],{"class":276},"sVXei","  loud",[230,279,280],{"class":269},"()",[230,282,284],{"class":283},"smGrS",":",[230,286,287],{"class":254}," Promise",[230,289,290],{"class":269},"\u003C",[230,292,293],{"class":254},"Reading",[230,295,296],{"class":265},"[]",[230,298,299],{"class":269},">",[230,301,302],{"class":269}," {\n",[230,304,306,309,313,316,319,323,326,329,331,335,338,341],{"class":232,"line":305},4,[230,307,308],{"class":243},"    return",[230,310,312],{"class":311},"s39Yj"," this",[230,314,315],{"class":269},".",[230,317,318],{"class":261},"findAllBy",[230,320,322],{"class":321},"skxfh","(",[230,324,325],{"class":269},"{",[230,327,328],{"class":321}," loud",[230,330,284],{"class":269},[230,332,334],{"class":333},"syTEX"," true",[230,336,337],{"class":269}," }",[230,339,340],{"class":321},")",[230,342,343],{"class":269},";\n",[230,345,347],{"class":232,"line":346},5,[230,348,349],{"class":269},"  }\n",[230,351,353],{"class":232,"line":352},6,[230,354,355],{"class":269},"}\n",[199,357,358],{},"Le handler pose la question, et n'épelle jamais le stockage :",[221,360,362],{"className":223,"code":361,"language":225,"meta":226,"style":226},"\u002F\u002F handlers\u002FReadingHandler.ts\nexport default class ReadingHandler {\n  constructor(private readings: ReadingRepository) {}\n\n  async loud() { return this.readings.loud(); }\n  async all()  { return this.readings.list(); }   \u002F\u002F les gestes du port, transmis\n}\n",[205,363,364,369,382,405,411,446,480],{"__ignoreMap":226},[230,365,366],{"class":232,"line":233},[230,367,368],{"class":236},"\u002F\u002F handlers\u002FReadingHandler.ts\n",[230,370,371,373,375,377,380],{"class":232,"line":240},[230,372,244],{"class":243},[230,374,247],{"class":243},[230,376,251],{"class":250},[230,378,379],{"class":254}," ReadingHandler",[230,381,302],{"class":269},[230,383,384,387,389,392,396,398,400,402],{"class":232,"line":273},[230,385,386],{"class":250},"  constructor",[230,388,322],{"class":269},[230,390,391],{"class":250},"private",[230,393,395],{"class":394},"s99_P"," readings",[230,397,284],{"class":283},[230,399,255],{"class":254},[230,401,340],{"class":269},[230,403,404],{"class":269}," {}\n",[230,406,407],{"class":232,"line":305},[230,408,410],{"emptyLinePlaceholder":409},true,"\n",[230,412,413,416,418,420,423,426,428,430,433,435,438,440,443],{"class":232,"line":346},[230,414,415],{"class":250},"  async",[230,417,328],{"class":276},[230,419,280],{"class":269},[230,421,422],{"class":269}," {",[230,424,425],{"class":243}," return",[230,427,312],{"class":311},[230,429,315],{"class":269},[230,431,432],{"class":265},"readings",[230,434,315],{"class":269},[230,436,437],{"class":261},"loud",[230,439,280],{"class":321},[230,441,442],{"class":269},";",[230,444,445],{"class":269}," }\n",[230,447,448,450,453,455,458,460,462,464,466,468,471,473,475,477],{"class":232,"line":352},[230,449,415],{"class":250},[230,451,452],{"class":276}," all",[230,454,280],{"class":269},[230,456,457],{"class":269},"  {",[230,459,425],{"class":243},[230,461,312],{"class":311},[230,463,315],{"class":269},[230,465,432],{"class":265},[230,467,315],{"class":269},[230,469,470],{"class":261},"list",[230,472,280],{"class":321},[230,474,442],{"class":269},[230,476,337],{"class":269},[230,478,479],{"class":236},"   \u002F\u002F les gestes du port, transmis\n",[230,481,483],{"class":232,"line":482},7,[230,484,355],{"class":269},[199,486,487,490,491,494],{},[205,488,489],{},"repositories\u002F"," est scanné comme ",[205,492,493],{},"services\u002F"," : la classe s'enregistre comme provider, et\nles dépendances de son constructeur se résolvent par type comme partout ailleurs.",[496,497,499],"h2",{"id":498},"nen-écrivez-aucun-et-vous-ne-perdez-rien","N'en écrivez aucun et vous ne perdez rien",[199,501,502,503,506,507,510],{},"Chaque entité a un repository, que vous ayez écrit le fichier ou non : le boot enregistre\nle port gardé sous ",[205,504,505],{},"\u003CEntité>Repository",". Un handler peut donc en demander un avant que\nquiconque ait écrit la classe, et en déclarer une plus tard l'emporte sous cette clé —\nexactement comme une opération ",[205,508,509],{},"Crud"," redéfinie dans une sous-classe l'emporte sur celle du\nprefab.",[199,512,513,514,517,518,521],{},"Les deux formes répondent aux mêmes noms, et c'est ce qui rend la convention vraie :\n",[205,515,516],{},"list()",", ",[205,519,520],{},"create()"," et les autres sont là dans les deux cas, une requête nommée est la\nseule différence.",[199,523,524],{},"Sans fichier écrit il n'y a pas de classe à désigner, alors nommez la forme :",[221,526,528],{"className":223,"code":527,"language":225,"meta":226,"style":226},"constructor(private nodes: RepositoryOf\u003CNode>) {}\n",[205,529,530],{"__ignoreMap":226},[230,531,532,535,538,540,543,545,548],{"class":232,"line":233},[230,533,534],{"class":261},"constructor",[230,536,537],{"class":265},"(private nodes: RepositoryOf",[230,539,290],{"class":283},[230,541,542],{"class":265},"Node",[230,544,299],{"class":283},[230,546,547],{"class":265},") ",[230,549,550],{"class":269},"{}\n",[199,552,553,556,557,560,561,556,564,567],{},[205,554,555],{},"RepositoryOf\u003CNode>"," est à ",[205,558,559],{},"NodeRepository"," ce que ",[205,562,563],{},"Storage\u003CNode>",[205,565,566],{},"NodeStorage"," : une\northographe d'une seule clé de conteneur.",[569,570,571],"warning",{},[199,572,573,574,577,578,580,581,584,585,588,589,592],{},"L'injection se fait sur le ",[216,575,576],{},"nom du type écrit sur le paramètre",", et la clé du conteneur\nest ",[205,579,505],{},". Une classe déclarée doit donc s'appeler ",[205,582,583],{},"ReadingRepository"," — pas\n",[205,586,587],{},"Readings",", pas ",[205,590,591],{},"ReadingQueries"," — sinon rien ne la résout.",[496,594,596],{"id":595},"le-port-nest-pas-un-mot-de-votre-vocabulaire","Le port n'est pas un mot de votre vocabulaire",[199,598,599,600,603],{},"Un handler, un presenter et un collector ne peuvent pas demander ",[205,601,602],{},"Storage\u003CE>",". Le boot le\nrefuse par son nom et désigne le repository :",[221,605,610],{"className":606,"code":608,"language":609},[607],"language-text","PostHandler asks for PostStorage. Storage is reached through a repository, never through\nthe port:\n    constructor(private post: PostRepository) {}\n","text",[205,611,608],{"__ignoreMap":226},[199,613,614],{},"Un seul chemin, et un seul mot pour le dire. Ce que ça achète au-delà de la propreté est le\nparagraphe ci-dessous : le jour où une entité appartient à un agrégat, aucun appel ne\nbouge, parce qu'aucun n'avait jamais épelé le stockage.",[199,616,617,618,621,622,627],{},"Un ",[216,619,620],{},"détenteur"," est l'exception, et c'est la même règle lue dans l'autre sens : une classe\nqu'un prefab a bâtie sur son entité peut nommer le port de cette entité, ce qui est la\nfaçon dont un ",[202,623,624],{"href":113},[205,625,626],{},"Mirror"," écrit la copie qu'il possède. Une porte juge\net projette ; un détenteur garde le stockage.",[496,629,631],{"id":630},"à-partir-de-deux-entités-il-les-possède","À partir de deux entités, il les possède",[199,633,634,635,638],{},"Le solde d'un compte et la somme des lignes de son journal sont un seul fait. Rien ne\npouvait le dire : le juge lit une ligne, et un ",[202,636,637],{"href":117},"cadre"," rend deux\nécritures atomiques sans dire lesquelles ont le droit d'arriver. Débitez 100 et journalisez\n50, la base accepte.",[199,640,641,642,645],{},"La moitié qui manquait n'a jamais été un vérificateur. C'était une porte : tant que\n",[205,643,644],{},"Storage\u003CLedger>"," est servi à qui le demande, aucun fichier ne peut être le seul chemin.\nNommez les deux entités et il en devient un :",[221,647,649],{"className":223,"code":648,"language":225,"meta":226,"style":226},"\u002F\u002F repositories\u002FAccountRepository.ts\nexport default class AccountRepository extends Repository(Account, Ledger) {\n  async withdraw(id: string, amount: number) {\n    const [accounts, ledger] = this.storages;\n    const account = await accounts.findById(id);\n    if (account!.balance \u003C amount) throw new Error('solde insuffisant');\n\n    await accounts.update(id, { balance: account!.balance - amount });\n    await ledger.create({ account: id, amount: -amount });\n  }\n}\n",[205,650,651,656,682,714,746,774,825,829,874,914,919],{"__ignoreMap":226},[230,652,653],{"class":232,"line":233},[230,654,655],{"class":236},"\u002F\u002F repositories\u002FAccountRepository.ts\n",[230,657,658,660,662,664,667,669,671,674,677,680],{"class":232,"line":240},[230,659,244],{"class":243},[230,661,247],{"class":243},[230,663,251],{"class":250},[230,665,666],{"class":254}," AccountRepository",[230,668,258],{"class":250},[230,670,262],{"class":261},[230,672,673],{"class":265},"(Account",[230,675,676],{"class":269},",",[230,678,679],{"class":265}," Ledger) ",[230,681,270],{"class":269},[230,683,684,686,689,691,694,696,700,702,705,707,710,712],{"class":232,"line":273},[230,685,415],{"class":250},[230,687,688],{"class":276}," withdraw",[230,690,322],{"class":269},[230,692,693],{"class":394},"id",[230,695,284],{"class":283},[230,697,699],{"class":698},"sZMiF"," string",[230,701,676],{"class":269},[230,703,704],{"class":394}," amount",[230,706,284],{"class":283},[230,708,709],{"class":698}," number",[230,711,340],{"class":269},[230,713,302],{"class":269},[230,715,716,719,722,726,728,731,734,737,739,741,744],{"class":232,"line":305},[230,717,718],{"class":250},"    const",[230,720,721],{"class":269}," [",[230,723,725],{"class":724},"s_hVV","accounts",[230,727,676],{"class":269},[230,729,730],{"class":724}," ledger",[230,732,733],{"class":269},"]",[230,735,736],{"class":283}," =",[230,738,312],{"class":311},[230,740,315],{"class":269},[230,742,743],{"class":265},"storages",[230,745,343],{"class":269},[230,747,748,750,753,755,758,761,763,766,768,770,772],{"class":232,"line":346},[230,749,718],{"class":250},[230,751,752],{"class":724}," account",[230,754,736],{"class":283},[230,756,757],{"class":243}," await",[230,759,760],{"class":265}," accounts",[230,762,315],{"class":269},[230,764,765],{"class":261},"findById",[230,767,322],{"class":321},[230,769,693],{"class":265},[230,771,340],{"class":321},[230,773,343],{"class":269},[230,775,776,779,782,785,788,790,793,796,798,800,803,806,809,811,815,819,821,823],{"class":232,"line":352},[230,777,778],{"class":243},"    if",[230,780,781],{"class":321}," (",[230,783,784],{"class":265},"account",[230,786,787],{"class":283},"!",[230,789,315],{"class":269},[230,791,792],{"class":265},"balance",[230,794,795],{"class":283}," \u003C",[230,797,704],{"class":265},[230,799,547],{"class":321},[230,801,802],{"class":243},"throw",[230,804,805],{"class":283}," new",[230,807,808],{"class":261}," Error",[230,810,322],{"class":321},[230,812,814],{"class":813},"sjJ54","'",[230,816,818],{"class":817},"s_sjI","solde insuffisant",[230,820,814],{"class":813},[230,822,340],{"class":321},[230,824,343],{"class":269},[230,826,827],{"class":232,"line":482},[230,828,410],{"emptyLinePlaceholder":409},[230,830,832,835,837,839,842,844,846,848,850,853,855,857,859,861,863,866,868,870,872],{"class":232,"line":831},8,[230,833,834],{"class":243},"    await",[230,836,760],{"class":265},[230,838,315],{"class":269},[230,840,841],{"class":261},"update",[230,843,322],{"class":321},[230,845,693],{"class":265},[230,847,676],{"class":269},[230,849,422],{"class":269},[230,851,852],{"class":321}," balance",[230,854,284],{"class":269},[230,856,752],{"class":265},[230,858,787],{"class":283},[230,860,315],{"class":269},[230,862,792],{"class":265},[230,864,865],{"class":283}," -",[230,867,704],{"class":265},[230,869,337],{"class":269},[230,871,340],{"class":321},[230,873,343],{"class":269},[230,875,877,879,881,883,886,888,890,892,894,897,899,901,903,905,908,910,912],{"class":232,"line":876},9,[230,878,834],{"class":243},[230,880,730],{"class":265},[230,882,315],{"class":269},[230,884,885],{"class":261},"create",[230,887,322],{"class":321},[230,889,325],{"class":269},[230,891,752],{"class":321},[230,893,284],{"class":269},[230,895,896],{"class":265}," id",[230,898,676],{"class":269},[230,900,704],{"class":321},[230,902,284],{"class":269},[230,904,865],{"class":283},[230,906,907],{"class":265},"amount",[230,909,337],{"class":269},[230,911,340],{"class":321},[230,913,343],{"class":269},[230,915,917],{"class":232,"line":916},10,[230,918,349],{"class":269},[230,920,922],{"class":232,"line":921},11,[230,923,355],{"class":269},[199,925,926],{},"La règle est du TypeScript ordinaire, dans la méthode qui écrit. Rien n'a été ajouté pour\nl'exprimer — ce qui a été ajouté, c'est que nulle part ailleurs ne peut écrire ces deux\ntables.",[199,928,929,932],{},[216,930,931],{},"L'arité est la déclaration."," Une entité est un endroit où nommer des questions ; deux ou\nplus est une frontière. Il n'y a aucun drapeau, et un repository d'une seule entité ne\npossède rien — une frontière entre une chose et rien n'est pas une frontière, et le juge\nsiège déjà sur les lignes de cette entité.",[199,934,935],{},"Trois choses en découlent, et chacune est la forme qui refuse plutôt qu'une règle écrite :",[937,938,939,950,963],"ul",{},[940,941,942,945,946,949],"li",{},[216,943,944],{},"Aucun repository par défaut"," n'est enregistré pour un membre. ",[205,947,948],{},"LedgerRepository","\nn'existe pas, donc rien ne peut le demander.",[940,951,952,955,956,958,959,962],{},[216,953,954],{},"Aucun geste n'est transmis."," Dans quelle entité ",[205,957,885],{}," écrirait-il ? La seule surface\nest donc ce que vous nommez. Une entité possédée n'a donc pas de CRUD automatique —\n",[205,960,961],{},"Crud(Ledger)"," n'a plus de stockage sur quoi tourner — et le boot le dit par son nom, au\nlieu de laisser l'application démarrer et échouer à sa première requête.",[940,964,965,968,969,972],{},[216,966,967],{},"Deux agrégats ne peuvent pas revendiquer une entité."," Refusé au boot en nommant les\ndeux, pour la raison qui fait ",[205,970,971],{},"ports:"," refuser deux implémentations : celui qui gagnerait\ndépendrait de l'ordre du scan, et l'une des deux frontières ne serait tenue par personne.",[974,975,977],"h3",{"id":976},"la-frontière-nest-pas-lunité-de-travail","La frontière n'est pas l'unité de travail",[199,979,980,981,983],{},"Un agrégat dit que les règles de ces entités tiennent ensemble. Un\n",[202,982,637],{"href":117}," dit que ces écritures atterrissent ensemble. Les deux\nlistes coïncident souvent, et ce ne sont pas le même énoncé — donc un cadre se demande ici\ncomme partout ailleurs :",[221,985,987],{"className":223,"code":986,"language":225,"meta":226,"style":226},"export default class AccountRepository extends Repository(Account, Ledger) {\n  constructor(\n    accounts: AccountStorage,\n    ledger: LedgerStorage,\n    private frame: Together\u003C[Account, Ledger]>,\n  ) { super(accounts, ledger); }\n\n  async withdraw(id: string, amount: number) {\n    return this.frame.run(async ([accounts, ledger]) => { \u002F* les deux, ou aucune *\u002F });\n  }\n}\n",[205,988,989,1011,1018,1031,1043,1074,1098,1102,1128,1175,1179],{"__ignoreMap":226},[230,990,991,993,995,997,999,1001,1003,1005,1007,1009],{"class":232,"line":233},[230,992,244],{"class":243},[230,994,247],{"class":243},[230,996,251],{"class":250},[230,998,666],{"class":254},[230,1000,258],{"class":250},[230,1002,262],{"class":261},[230,1004,673],{"class":265},[230,1006,676],{"class":269},[230,1008,679],{"class":265},[230,1010,270],{"class":269},[230,1012,1013,1015],{"class":232,"line":240},[230,1014,386],{"class":250},[230,1016,1017],{"class":269},"(\n",[230,1019,1020,1023,1025,1028],{"class":232,"line":273},[230,1021,1022],{"class":394},"    accounts",[230,1024,284],{"class":283},[230,1026,1027],{"class":254}," AccountStorage",[230,1029,1030],{"class":269},",\n",[230,1032,1033,1036,1038,1041],{"class":232,"line":305},[230,1034,1035],{"class":394},"    ledger",[230,1037,284],{"class":283},[230,1039,1040],{"class":254}," LedgerStorage",[230,1042,1030],{"class":269},[230,1044,1045,1048,1051,1053,1056,1058,1061,1064,1066,1069,1071],{"class":232,"line":346},[230,1046,1047],{"class":250},"    private",[230,1049,1050],{"class":394}," frame",[230,1052,284],{"class":283},[230,1054,1055],{"class":254}," Together",[230,1057,290],{"class":269},[230,1059,1060],{"class":265},"[",[230,1062,1063],{"class":254},"Account",[230,1065,676],{"class":269},[230,1067,1068],{"class":254}," Ledger",[230,1070,733],{"class":265},[230,1072,1073],{"class":269},">,\n",[230,1075,1076,1079,1081,1084,1086,1088,1090,1092,1094,1096],{"class":232,"line":352},[230,1077,1078],{"class":269},"  )",[230,1080,422],{"class":269},[230,1082,1083],{"class":724}," super",[230,1085,322],{"class":321},[230,1087,725],{"class":265},[230,1089,676],{"class":269},[230,1091,730],{"class":265},[230,1093,340],{"class":321},[230,1095,442],{"class":269},[230,1097,445],{"class":269},[230,1099,1100],{"class":232,"line":482},[230,1101,410],{"emptyLinePlaceholder":409},[230,1103,1104,1106,1108,1110,1112,1114,1116,1118,1120,1122,1124,1126],{"class":232,"line":831},[230,1105,415],{"class":250},[230,1107,688],{"class":276},[230,1109,322],{"class":269},[230,1111,693],{"class":394},[230,1113,284],{"class":283},[230,1115,699],{"class":698},[230,1117,676],{"class":269},[230,1119,704],{"class":394},[230,1121,284],{"class":283},[230,1123,709],{"class":698},[230,1125,340],{"class":269},[230,1127,302],{"class":269},[230,1129,1130,1132,1134,1136,1139,1141,1144,1146,1149,1152,1154,1156,1158,1161,1164,1166,1169,1171,1173],{"class":232,"line":876},[230,1131,308],{"class":243},[230,1133,312],{"class":311},[230,1135,315],{"class":269},[230,1137,1138],{"class":265},"frame",[230,1140,315],{"class":269},[230,1142,1143],{"class":261},"run",[230,1145,322],{"class":321},[230,1147,1148],{"class":250},"async",[230,1150,1151],{"class":269}," ([",[230,1153,725],{"class":394},[230,1155,676],{"class":269},[230,1157,730],{"class":394},[230,1159,1160],{"class":269},"])",[230,1162,1163],{"class":250}," =>",[230,1165,422],{"class":269},[230,1167,1168],{"class":236}," \u002F* les deux, ou aucune *\u002F",[230,1170,337],{"class":269},[230,1172,340],{"class":321},[230,1174,343],{"class":269},[230,1176,1177],{"class":232,"line":916},[230,1178,349],{"class":269},[230,1180,1181],{"class":232,"line":921},[230,1182,355],{"class":269},[199,1184,1185,1186,1189],{},"Dériver le cadre de la composition aurait fait porter un cadre à un agrégat en lecture seule\n— ses refus compris — et mis ",[205,1187,1188],{},"Together\u003C[Account, Ledger], [RateMirror]>"," hors d'atteinte\npour toujours.",[199,1191,1192,1193,1195],{},"Les noms du port reviennent dans ce constructeur, et là seulement : cette classe ",[216,1194,218],{}," le\ndétenteur, ce qui est le seul cas que la règle ci-dessus autorise.",[496,1197,1199],{"id":1198},"ce-nest-pas-une-porte","Ce n'est pas une porte",[199,1201,1202,1203,1206,1207,1210],{},"Un repository n'a pas de façade : rien de ce qu'il porte n'est atteignable depuis le fil.\nC'est ce qui le laisse libre de tenir tout ce que le domaine demande — mais cela veut dire\naussi qu'un ",[216,1204,1205],{},"juge n'a rien à faire ici",". Les règles sur qui a le droit d'agir restent dans\nle ",[202,1208,1209],{"href":85},"handler",", le seul endroit qu'un refus ne peut pas\ncontourner. Ce qui appartient ici est l'autre sorte : une règle sur ce que la donnée peut\nêtre.",[199,1212,1213],{},"Les écritures restent jugées, parce qu'elles passent par le port : une valeur que l'entité\ninterdit est refusée, que ce soit un repository ou un handler qui l'émette.",[199,1215,1216,1217,315],{},"Suite : ",[202,1218,88],{"href":89},[1220,1221,1222],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sVXei, html code.shiki .sVXei{--shiki-light:#E53935;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":226,"searchDepth":240,"depth":240,"links":1224},[1225,1226,1227,1230],{"id":498,"depth":240,"text":499},{"id":595,"depth":240,"text":596},{"id":630,"depth":240,"text":631,"children":1228},[1229],{"id":976,"depth":273,"text":977},{"id":1198,"depth":240,"text":1199},"Qui possède le stockage d'une entité — le seul chemin, le défaut qu'on obtient sans rien écrire, et ce qui change à partir de deux entités.","md",{},{"title":120,"description":1231},"bRdcVL_8NPwN3yChpceg6FyUXKDlyrzHlCB_eZsynt4",1788598419413]