To download the Sequential ID Generator, visit: [tulip](https://<span translate=).co/library/apps/sequential-id-generator---multiple-prefix-support">Library
Ebben a cikkben Tamás, a könyvtár egyik fejlesztője, bemutatja a könyvtárban elérhető „Sequential ID Generator” építőelem-alkalmazás fejlesztése során hozott döntéseket.
Miért így készítettem el
Azt akartam, hogy ez a logikai blokk egy nagyon gyakorlati problémát oldjon meg: olyan módon generáljon azonosítókat, amely megbízható, könnyen újrahasznosítható és gyorsan bevezethető számos alkalmazásban.
A legfontosabb tervezési cél nem csupán az volt, hogy „generálja a következő számot”. Az igazi cél az volt, hogy olyasmit hozzak létre, amit egyszer definiálva nagyon kis erőfeszítéssel lehet másolni és újra felhasználni. Ha egy gombot egyszer tisztán megalkotnak, akkor lehetővé kell tenni, hogy azt egy másik alkalmazásba vagy egy másik lépésbe helyezzék, és csak a konfigurációt kelljen módosítani. Nem akartam, hogy minden alkalmazásfejlesztőnek minden alkalommal újra kelljen nyitnia a logikát és újra kelljen írnia a kiváltókat.
Éppen ezért a logikai blokkot úgy tervezték, hogy a logika helyett a konfigurációt helyezze előtérbe. Amikor ezt a logikai blokkot használja, leginkább a következőkre kell figyelnie:* milyen előtagra van szükség* milyen hosszú legyen a számrész* melyik táblából olvassa ki az adatot a gomb
Miután meghatároztad az előtagot, a számformátumot és a táblát, a logikai blokkoknak már el kell intézniük a többit: kiolvasni a legfrissebb azonosítót, érvényesíteni azt, generálni a következő értéket, és ellenőrizni, hogy a szám továbbra is illeszkedik-e a beállított hosszúsághoz.
Maga a táblázatnak kell a hiteles forrásnak lennie. Egy különálló számláló (amely például egy változó is lehet) eltérhet a valós adatoktól, ha a rekordokat váratlan módon illesztik be, törlik vagy szerkesztik. A táblázatból való kiolvasás biztosítja, hogy a számozás a ténylegesen létező adatokhoz igazodjon.
Egy másik fontos döntés az volt, hogy a számítás alapvető logikáját egy helyen tartsam. Nem akartam, hogy az első azonosítóhoz egy trigger-ág, a következő azonosítóhoz egy másik ág tartozzon, majd pedig további apró trigger-töredékek, amelyek később nehezen követhetők. Azt akartam, hogy a fő logika egy expression -ben legyen, így a viselkedés konzisztens marad, és aki később módosítja, pontosan tudja, hol keresse.
A logikai blokk tehát valójában néhány gyakorlati döntésen alapul:* könnyen másolható és újrahasznosítható* elég biztonságos ahhoz, hogy megvédje a táblát a hibás azonosító-mintáktól* egyszerűen konfigurálható* központosított logika, így a karbantartás kezelhető marad
Hogyan néz ki az azonosító?
Minden generált azonosító két részből áll:előtag + numerikus sorozat
Példák:* ORD00000125* MAT00000003* TEST00004567
Az előtag jelzi, hogy milyen típusú rekordról van szó. A numerikus rész a futó sorszám. Úgy döntöttem, hogy a numerikus formátum konfigurációját nagyon egyszerűen tartom. Ahelyett, hogy a felhasználótól külön számot kérnék, például „8 számjegyet”, a logikai blokk egy nullás mintát használ, például:* 00000000
Ez egy pillantásra könnyebben olvasható. Ha valaki nyolc nullát lát, azonnal megérti, hogy a számrésznek mindig nyolc karakter hosszúnak kell lennie. Ezért tartottam meg az idNumberFormat-ot ebben a formában, ahelyett, hogy egy puszta hosszúsági mezővel helyettesítettem volna.
Példák:* 00000000 → 8 számjegyű szám* 0000 → 4 számjegyű szám
Ez a döntés apró, de fontos. Könnyebben érthetővé teszi a logikai blokkot azok számára, akik nem akarnak technikai paraméterekben gondolkodni.
A build felépítése
A tényleges megvalósítás három triggert használ. Ez a felépítés szándékos. Azt akartam, hogy a logikai blokk felülről lefelé könnyen követhető legyen, miközben a fő logika elkülönüljön és újrafelhasználható maradjon. Így ahelyett, hogy a logikát számos szerkeszthető triggerre osztottam volna szét, három szakaszba szerveztem:1. FELHASZNÁLÓI BEÁLLÍTÁS: BEMENETI SZAKASZ 2. MAGIC 3. FELHASZNÁLÓI BEÁLLÍTÁS: KIMENETI SZAKASZ
Ez jó egyensúlyt teremt a használhatóság és az irányítás között.* Az első triggerben határozzuk meg a bemeneteket.* A második trigger tartalmazza a belső logikát, amelyet általában nem kell szerkeszteni ahhoz, hogy a logikai blokk működjön.* A harmadik triggerben döntjük el, mit kezdjünk a generált eredménnyel.
Ez azt jelenti, hogy általában nem kell a maglogikai triggeren belül dolgoznia. Csak a bemeneti és a kimeneti oldalt kell konfigurálnia. Ez volt az egyik legfontosabb tervezési döntés: a logikai blokk újrafelhasználhatóvá tétele azáltal, hogy csak azokat a részeket tesszük elérhetővé, amelyeket általában módosítani kell.
1. trigger – FELHASZNÁLÓI BEÁLLÍTÁS: BEMENETI SZAKASZ
Ez az első trigger, amellyel interakcióba lép. Célja, hogy meghatározza azokat a bemeneti értékeket, amelyekre a logikai blokknak szüksége van, mielőtt bármilyen azonosító generálható lenne.A gyakorlatban ezt a triggert a következők meghatározására használják:* az előtag* az idNumberFormat* a csatlakozóba átadott táblázat-azonosító Példa: előtag = ORDidNumberFormat = 00000000 táblázat-azonosító = cél táblázat
Ez a szakasz szándékosan szerkeszthető, mivel ezek azok az értékek, amelyek általában használati esetenként változnak.
Ugyanezt a gombot átmásolhatja egy másik alkalmazásba vagy lépésbe, frissítheti ezeket a konfigurációs értékeket, és újra felhasználhatja a logikai blokkot anélkül, hogy a belső logikát módosítaná.
Ez gyorsabb megvalósítást tesz lehetővé, mivel a bemeneti értékek meghatározása után a folyamat többi része automatikusan működik. Ez a trigger futtatja azt a csatlakozóhívást is, amely a kiválasztott táblából kiolvassa a legfrissebb, megfelelő rekordot.
Miért része a csatlakozó a tervezésnek?
A csatlakozó nem csupán egy technikai részlet. A újrafelhasználási stratégia része. A csatlakozót arra használom, hogy kiolvassam a cél táblából a legfrissebb létező azonosítót. A csatlakozó bemenetként megkapja a táblázat azonosítóját, alkalmazza az előtagszűrőt, csökkenő sorrendbe rendezi a rekordokat a _sequenceNumber szerint, majd visszaadja a legfrissebb, megfelelő rekordot. Ez két okból is fontos. Először is, lehetővé teszi, hogy a logikai blokk a táblázat tényleges állapotától folytassa a számozást. Másodszor, így a logikai blokk újrafelhasználása sokkal egyszerűbbé válik. Ha a gombot másik alkalmazásba másolja, nem kell újraírnia a logikát. Csak a csatlakozót kell a megfelelő táblára irányítania, és megadnia a szükséges konfigurációt. Ez a gyakorlati minta áll a felépítés mögött: 1. egyszer létrehozza a gombot; 2. beállítja a táblabemenetet a csatlakozóban; 3. meghatározza az előtagot és a számformátumot; 4. újrahasznosítja, ahol csak szükséges.
Ez egy tudatos döntés volt, amelynek célja az alkalmazások gyorsabb fejlesztésének támogatása.
Mit csinál a csatlakozó a logikai blokkban?
Mi történik itt: * a csatlakozó megkapja a táblázat azonosítóját * a csatlakozó megkapja az előtagot * a csatlakozó az előtag szerint szűri a rekordokat * a csatlakozó a _sequenceNumber szerint csökkenő sorrendbe rendezi a rekordokat * a csatlakozó visszaadja a legújabb egyező azonosítót
A csatlakozó egy nagyon fontos felhasználási esetet is támogat: több entitás ugyanabban a táblában.
Ha ugyanaz a táblázat olyan rekordokat tartalmaz, mint: ORD00000011 MAT00000003, akkor a logikai blokknak nem szabad őket egyetlen közös sorozatként kezelnie. Minden előtag csak a saját legfrissebb értékétől folytathatja a sorozatot.
Így a csatlakozó először előtag szerint szűri a rekordokat. Ez azt jelenti, hogy a következő értékek a következők lesznek: ORD → ORD00000012, MAT → MAT00000004
Ezt a modellt azért választottam, mert ugyanabban a táblában különböző entitások is szerepelhetnek, de ez nem jelenti azt, hogy ugyanazt a sorszámot kellene megosztaniuk.
Egy beállítási követelményt is érdemes egyértelműen megemlíteni: a csatlakozónak hitelesítésre van szüksége, ezért létre kell hozni egy tokent, és hozzá kell adni a csatlakozó hitelesítési beállításaihoz. Ezt beállítási munkának tekintem, nem a logikai blokk logikájának részének, de mégis fontos része annak, hogy a logikai blokk használható legyen.
Ezt a bemeneti szakaszban hagytam, mert a beállításhoz és a kontextusgyűjtéshez tartozik. Mielőtt a belső logika működni tudna, a logikai blokknak először tudnia kell, mivel dolgozik.
2. kiváltó – MAGIC
Ez a logika központi triggerje. Szándékosan neveztem el így. Az elképzelés egyszerű: ez az a rész, amelyet általában nem kellene szerkesztenie. A logikai blokknak már eleve magában kell hordoznia ezt a logikát. Ez a trigger felveszi a konfigurált bemeneti értékeket és az előző trigger által visszaadott legfrissebb azonosítót, majd elvégzi a belső döntéshozatalt. Annak ellenére, hogy ez egyetlen trigger, belül több dolog is történik.
1. Formátumellenőrzés – a trigger „if” része
Az első ellenőrzés megvizsgálja, hogy a táblából visszaküldött legutóbbi azonosító még mindig megfelel-e a várt szerkezetnek. Várt szerkezet: **előtag + fix hosszúságú szám
Példa érvényes értékre: ORD00000025 Példák érvénytelen értékekre: ORD25, ORD-00025, ABC00000025, ORD00025A
Expression
REGEX_REPLACE( LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat), '^' + Variable._configPrefix + '[0-9]{' + LEN(Variable._configIdNumberFormat) + '}$', 'ok')
Mit csinál ez a expression?
Ez az expression ellenőrzi, hogy a legújabb azonosító pontosan megfelel-e a logikai blokk által elvárt szerkezetnek. Ezt három lépésben végzi el:* A LINK(...) meghatározza, melyik értéket kell ellenőrizni. Ha a csatlakozó nem ad vissza azonosítót, akkor helyette a második rész kerül felhasználásra. Ez a második rész a konfigurált kezdő szerkezet, amely lehetővé teszi a logikai blokk számára, hogy létrehozza az első azonosítót egy új előtag-sorozathoz.* A '^' + Variable._configPrefix azt jelenti, hogy az értéknek a konfigurált előtaggal kell kezdődnie.* A '[0-9]{' + LEN(Variable._configIdNumberFormat) + '}$' azt jelenti, hogy az értéknek pontosan a várt számú számjeggyel kell végződnie, és utána semmi más nem megengedett.
Ha az egész érték megfelel a várt szerkezetnek, az eredmény „ok” lesz. Ha nem felel meg, az „ expression ” eredmény továbbra is eltér az „ok”-tól, és a trigger leállítja a generálási folyamatot, és hibaüzenetet jelenít meg
Miért választottam ezt?
Azért adtam hozzá ezt az ellenőrzést, mert nem akartam, hogy a logikai blokk egy hibás formátumú azonosítóból folytassa a feldolgozást. Ha a legutóbb tárolt érték hibás, és a logika elfogadja, akkor a hibás minta elkezdhet terjedni a jövőbeli rekordokba. Ezért azt akartam, hogy a MAGIC trigger elsődleges feladata az legyen, hogy ezt már korán megakadályozza. Ha a formátum hibás: * a _stateOutput törlődik * megjelenik egy üzenet, amely elmagyarázza, miért állt le a generálás
2. Túlcsordulás-ellenőrzés
A második ellenőrzés a következő numerikus értéket vizsgálja, és ellenőrzi, hogy az továbbra is belefér-e a beállított numerikus hosszúságba.
Példa: idNumberFormat = 0000
Megengedett tartomány: 0000–9999
Ha a következő érték: 10000 lenne, akkor az már nem illeszkedne a beállított szerkezetbe.
Expression
LEN(Variable._configIdNumberFormat) < LEN( TOTEXT( TEXTTOINTEGER( REGEX_REPLACE( LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat), '^' + Variable._configPrefix, '' ) ) + 1 ))
Mit csinál ez a expression?
Ez az expression két hosszúságot hasonlít össze:* a megengedett numerikus hosszúságot, amelyet az idNumberFormat-ból vesz* a jelenlegi érték növelése után következő szám hosszúságát
A jobb oldal így működik:* A LINK(...) a csatlakozó által visszaadott azonosítót használja, ha van ilyen. Ha a csatlakozó nem ad vissza azonosítót, akkor a konfigurált kezdőstruktúrát használja helyette. Ez teszi lehetővé az első azonosító generálását.* A REGEX_REPLACE(...) eltávolítja az előtagot, így csak a numerikus rész marad meg* A TEXTTOINTEGER(...) + 1 kiszámítja a következő numerikus értéket* A TOTEXT(...) visszaalakítja azt a következő értéket szöveggé* A LEN(...) megméri, hány számjegyre van szüksége a következő értéknek
Ha a következő számhoz több számjegy szükséges, mint amennyit a formátum megenged, a feltétel igaznak bizonyul, és a trigger leállítja a folyamatot.
Miért ezt választottam
Úgy döntöttem, hogy itt leállítom a folyamatot, ahelyett, hogy automatikusan megváltoztatnám a struktúrát. Ez a döntés azért volt fontos, mert azt akartam, hogy az azonosító hossza stabil maradjon, hacsak valaki kifejezetten nem módosítja a konfigurációt. Ha túlcsordulást észlel:* a _stateOutput törlődik* megjelenik egy üzenet, amely elmagyarázza, hogy elérte a maximális hosszúságot
3. Az azonosító generálása
Ha mindkét ellenőrzés sikeres, a trigger generálja a következő azonosítót. Példa: ORD00000015 → ORD00000016
Ugyanez az expression kezeli azt az esetet is, amikor még nem létezik rekord az adott előtaghoz. Ebben az esetben a logika visszatér a konfigurált kezdő szerkezethez, és létrehozza a sorozat első értékét. Példa: ORD00000001
Expression
Variable._configPrefix + RIGHT( Variable._configIdNumberFormat + TOTEXT( TEXTTOINTEGER( REGEX_REPLACE( LINK(Variable._stateLastId.id, Variable._configPrefix + Variable._configIdNumberFormat), '^' + Variable._configPrefix, '' ) ) + 1 ), LEN(Variable._configIdNumberFormat))
Mit csinál ez az expression?
Ez az a „ expression ”, amely létrehozza a végleges azonosítót. A következő sorrendben működik:* A LINK(...) a csatlakozó által visszaadott utolsó azonosítót használja, ha van ilyen. Ha a csatlakozó nem ad vissza azonosítót, akkor a konfigurált kezdőstruktúrát használja helyette. Ez teszi lehetővé, hogy ugyanaz a „ expression ” kezelje az első generált azonosítót is.* A REGEX_REPLACE(...) eltávolítja az előtagot, hogy a numerikus rész feldolgozható legyen* A TEXTTOINTEGER(...)+ 1 növeli a számot* A TOTEXT(...) visszaalakítja az új számot szöveggé* A Variable._configIdNumberFormat + ... hozzáadja a nulla mintát az új érték elé* A RIGHT(..., LEN(Variable._configIdNumberFormat)) csak a szükséges számú számjegyet tartja meg* A Variable._configPrefix + ... visszaadja az előtagot a végleges azonosító létrehozásához. Az eredményt a _stateOutput tárolja.
Miért választottam ezt
Szándékosan egyetlen központi expression-ként tartottam meg ezt. Ha tehettem, nem akartam külön belső ágakat az első azonosítóhoz és a következő azonosítóhoz. A számítás egy helyen tartása megkönnyíti az újrafelhasználást és biztonságosabbá teszi a jövőbeli változtatásokat. A trigger végén a generált érték a _stateOutput-ban kerül tárolásra.
3. trigger – FELHASZNÁLÓI BEÁLLÍTÁSOK: KIMENETI SZAKASZ
Ez a logikai blokk utolsó triggerje. Célja annak meghatározása, hogy mi történjen a generált azonosítóval, miután a _stateOutput érvényes értéket tartalmaz. Itt fontos kiemelni, hogy ezt a szakaszt szándékosan nyitva hagytuk az Ön számára. Ha a _stateOutput nem üres, akkor Ön döntheti el, hogy a logikai blokk mit tegyen ezután.A jelenlegi beállításban a trigger egy útmutató üzenetet jelenít meg, amely elmagyarázza, mi a teendő:* adja hozzá a konfigurált táblázatot az alkalmazáshoz* cserélje ki ezt az üzenetlépést egy „Create Record” triggerre* használja az _stateOutput-ot az új rekord azonosítójának
Azért építettem így, mert a kimeneti viselkedés az egyes felhasználási esetek között eltérő lehet. Lehet, hogy azonnal létre szeretne hozni egy rekordot. Lehet, hogy először egy másik változóban szeretné tárolni az értéket. Vagy esetleg egy nagyobb munkafolyamatban szeretné felhasználni, mielőtt bármit is írna a táblába. Ezért ahelyett, hogy egy rögzített kimeneti viselkedést programoztam volna be, a kimeneti szakaszt konfigurálhatóvá tettem. Ezért van a felhasználó számára látható rész mindkét végén:* a bemenet konfigurálható* a kimenet konfigurálható* a maglogika középen marad
Miért vannak így elválasztva a kiváltók?
Ez a felépítés az egész logikai blokk egyik legfontosabb tervezési döntését tükrözi: a felelősségi köröket szét kell választani, de a maglogikát központosítva kell tartani.Ezért nem tettem mindent egyetlen hatalmas triggerbe. Egyetlen óriási trigger talán működne, de nehezebb lenne olvasni, nehezebb lenne elmagyarázni, és nehezebb lenne hibakeresni. Másrészt a tényleges matematikai műveletek sok apró darabra bontása is zavarossá válik. Ezért egy középutat választottam:* külön trigger-ek az olvasható lépésekhez* egy központosított „ expression ” a tényleges azonosító kiszámításához
Így mindkét megoldás előnyeit élvezhetem:* a kód könnyebben követhető* a logika könnyebben karbantartható* az újrafelhasználás egyszerűbb* a jövőbeli módosítások kevésbé kockázatosak
Miért fontos az érvényesítés és a védelem ebben a logikai blokkban
Ez a logikai blokk nem csupán a következő szám generálásáról szól. Arról is szól, hogy megvédje a táblázatot a hibás adatoktól. Két fő védelmi pont van:
Formátumvédelem
A logikai blokk ellenőrzi, hogy az utolsó létező azonosító megfelel-e a várt szerkezetnek, mielőtt továbbhaladna. Ez megakadályozza, hogy a sorozat olyan azonosítók alapján folytatódjon, amelyek nem felelnek meg a várt szerkezetnek.
Túlcsordulás elleni védelem
A logikai blokk ellenőrzi, hogy a következő szám még belefér-e a megengedett numerikus hosszúságba. Ez megakadályozza, hogy a sorozat növekedése során a szerkezet váratlanul megváltozzon. Mindkét szempontot fontosnak tartottam, mivel a hibás azonosítóadatok gyorsan terjedhetnek. Ha egyszer egy helytelen minta bekerül a táblába, és a generátor elkezdi használni, az a probléma hatással lehet minden jövőbeli rekordra. Ezért a logikai blokkot úgy tervezték, hogy korán leálljon, ahelyett, hogy csendben folytatná a munkát a helytelen irányba.
Változónevezési megközelítés
Talán észrevetted, hogy a logikai blokkban használt változónevek egy meghatározott mintát követnek. Példák:_configPrefix, _configIdNumberFormat, _stateLastId, _sequenceNumber
Szándékosan olyan névadási stílust alkalmaztam, amely könnyen megkülönböztethető az alkalmazásokon belül általában létrehozott változóktól. Ennek célja nem technikai, hanem gyakorlati. Amikor a logikai blokkot importálja vagy másolja egy alkalmazásba, azonnal láthatónak kell lennie, hogy mely változók tartoznak a logikai blokkhoz, és melyek az alkalmazás logikájához.A logikai blokk változói egységes szerkezetet követnek, így vizuálisan egy csoportba tartoznak, és kevésbé valószínű, hogy ütköznek a felhasználó által definiált változókkal. Ez megkönnyíti a logikai blokk újrafelhasználását, és biztonságosabbá teszi a meglévő alkalmazásokba való integrálását, anélkül, hogy névváltoztatási ütközések vagy zavarok keletkeznének.
A fejlesztési döntések összefoglalása
Ha az egész logikai blokkot a mögötte álló alapvető döntésekre redukálom, azok a következők:* Gyors újrafelhasználhatóságot akartam, ezért a logikai blokk konfigurációvezérelt.* Azt akartam, hogy a táblázat legyen a hiteles forrás, ezért a következő azonosító a legfrissebb valós rekordon alapul.* Azt akartam, hogy a logika karbantartható maradjon, ezért a számítás központosított.* Azt akartam, hogy egy táblában több entitás is zökkenőmentesen működjön, ezért minden előtaghoz saját sorozata tartozik.* Azt akartam, hogy a táblát megvédjem a helytelen mintázatoktól, ezért a formátum- és túlcsordulás-ellenőrzések még a rekord létrehozása előtt megakadályozzák a hibás adatok bejutását.* Azt akartam, hogy a trigger folyamat olvasható legyen, ezért a feladatok egyértelmű lépésekre vannak felosztva.
Ezért néz ki így a logikai blokk. Ez nem csupán egy azonosító-generátor. Ez egy újrafelhasználható minta az ellenőrzött azonosító-létrehozáshoz, amely megpróbálja egyensúlyba hozni az egyszerűséget, az újrafelhasználhatóságot és az adatvédelmet.
Csatlakozz hozzánk
Csatlakozz a közösséghez, hogy megoszthasd a fejlesztéseket, további egységeket javasolhass, hibákat jelenthess, vagy megvitathasd az architektúrával kapcsolatos döntéseket.
