dimesum

Forside / Blog / Penge

Penge

Derfor skal en redigering angive fordelingen igen

· 8 min læsning ·

En redigerings standardværdier er pengefejl, så Dimesum kræver participants og split_type på hver udgifts-PATCH sammen med base_version, der afviser en forældet redigering frem for at flette den.

At rette en tastefejl bør ikke ændre, hvem der skylder penge. I Dimesum angiver en redigering af en delt udgift hele fordelingen igen. participants og split_type er påkrævet på hver PATCH, og en redigering, der udelader en af dem, kommer tilbage med 400 i stedet for at udfylde en standardværdi. Standardværdierne ved oprettelse er alle nuværende medlemmer og en lige fordeling, hvilket ved en redigering er pengefejl.

To fejl gør sagen konkret. En bofælle, der flyttede ind i august, bliver trukket ind i juli måneds middag, fordi "alle nuværende medlemmer" bliver vurderet, når redigeringen lander, ikke da udgiften blev skrevet. En bevidst 70/30-fordeling af husleje flades ud til 50/50, fordi et manglende split_type betyder EQUAL. Ingen af fejlene udløser en fejlmeddelelse, og begge flytter rigtige penge.

Holdningen

En redigerings standardværdier er pengefejl. En standardværdi ved oprettelse gætter på den gruppe, forfatteren ser på lige nu. En redigering ankommer senere, mod en gruppe, der har flyttet sig, og det samme gæt omskriver stille, hvad folk skylder.

Standardværdier ved oprettelse beskriver en ny udgift, ikke en gammel

Ved oprettelse er standardværdierne ærlige. Forfatteren ser på gruppen, som den er, og en lige fordeling mellem alle er det almindelige tilfælde, så Dimesum udfylder begge. Udgiften gemmer sine inputs frem for kun sine resultater: splits.percent_bp, splits.weight og splits.exact_minor bevarer, hvad brugeren skrev, så en senere redigering kan åbne den igen.

En redigering er en anden handling. Den samme udgift kan blive rettet uger senere, når en ny bofælle er flyttet ind, eller et spøgelsesmedlem er blevet gjort krav på. Medlemskab er et bevægeligt mål, og fordelingen er ikke. At genbruge standardværdierne fra oprettelse beder dagens gruppe om at besvare et spørgsmål, som den gamle udgift allerede har besvaret.

To versioner af den samme redigering: nedarvede standardværdier ændrer hver andel, mens en genangivet fordeling kun ændrer beskrivelsen REDIGERING ARVER STANDARDVÆRDIERNE REDIGERING ANGIVER FORDELINGEN IGEN Husleje, 20,000 kroner, juli Husleje, 20,000 kroner, juli v1 Asha 70%, 14,000 Bhavna 30%, 6,000 v1 Asha 70%, 14,000 Bhavna 30%, 6,000 Chetan flytter ind i lejligheden i august. Chetan flytter ind i lejligheden i august. PATCH retter en tastefejl, sender ingen fordeling. PATCH retter en tastefejl, sender fordelingen: participants: Asha, Bhavna split_type: PERCENT 7000 / 3000 v2 Asha 6,666.67 Bhavna 6,666.67 Chetan 6,666.66 v2 Asha 70%, 14,000 Bhavna 30%, 6,000 Chetan skylder for en måned, han aldrig boede. Kun beskrivelsen ændrede sig.
Den samme redigering på ét tegn, to gange. At arve standardværdierne fra oprettelse deler 20,000 kroner op på tre og opkræver et medlem, der flyttede ind en måned senere; at angive fordelingen igen lader hver andel være urørt.

Afvisningen af at gætte er ikke ny her. En udgift med flere betalere skal også angive sine betalere igen. soleStoredPayer genbruger kun den gemte betaler, når udgiften har præcis én, så en redigering, der tier om to betalere, bliver afvist frem for at blive omfordelt. En redigering, der intet siger om betalere, beholder udgiftens egen betaler, aldrig den person, der foretager redigeringen.

API'et afviser en redigering, der ikke angiver sin fordeling igen

Kontrollen i gatewayen kører, før nogen penge bliver beregnet. Når participants er tom, eller split_type er blank, kommer forespørgslen tilbage med 400 med koden invalid_expense og beskeden "an edit must restate the split: participants and split_type are required". Udgiftstjenesten gentager reglen i validateAmend, så en kalder, der når tjenesten på en anden måde, møder den samme afvisning.

Hvad en oprettelse sender kontra hvad en redigering skal angive igen, på POST og PATCH /v1/groups/{id}/expenses.
FeltVed oprettelseVed en redigeringHvad standardværdien ville koste
participantsValgfri. Standard er alle nuværende medlemmerPåkrævetEt medlem, der flyttede ind bagefter, kommer med i en gammel udgift
split_typeValgfri. Standard er EQUALPåkrævetEn 70/30-fordeling flades ud til 50/50
payersValgfri. Standard er forfatterenUdeladt beholder udgiftens eneste betaler; to betalere skal angives igenDen, der redigerer, bliver betaleren og vender om på, hvem der skylder hvem
base_versionSendes ikkePåkrævet og skal svare til den nuværende versionEn forældet redigering overskriver en ændring, dens forfatter aldrig læste
revision_idKlient-UUIDv7, idempotensnøglenSamme, én pr. versionEn genforsøgt redigering opkræver gruppen to gange
currencyAngivet pr. udgiftSkal stemme; en ændring bliver afvistEn saldorække rummer én valuta pr. medlem

Valuta hører til den samme familie af afvisninger. En redigering kan ikke omdenominere en udgift, fordi en saldorække rummer én valuta pr. medlem. Skrivesiden afviser ændringen, og append-only-hovedbogen parkerer en sådan ændring, hvis en nogensinde når frem til den. At afvise ved døren holder de to halvdele fra at være uenige.

En forældet redigering bliver afvist til sin forfatter, aldrig flettet

base_version er den anden halvdel af kontrakten. Hver PATCH bærer den version, dens forfatter læste, og checkTransition sammenligner den med den række, transaktionen netop har låst. Er de ens, gælder redigeringen ved version plus én. Er de forskellige, får kalderen HTTP 409 med koden stale_version.

Fletning er det fristende alternativ, og det er forkert. To redigeringer af én udgift er to fuldstændige udsagn om, hvad regningen betyder. At flette dem frembringer et tredje udsagn, som ingen skrev, med andele, som ingen af forfatterne ville genkende. Afvisning giver konflikten tilbage til den ene person, der kan løse den.

To forfattere læser version 3; den første redigering bogfører version 4, og den anden bliver afvist med 409 stale_version udgift, version 3 Forfatter A PATCH base_version: 3 200 OK, version 4 Forfatter B PATCH base_version: 3 409 stale_version Hovedbog, én transaktion: EXPENSE_REVERSAL af v3 EXPENSE v4 Forfatter B læser version 4 igen, anvender ændringen igen, sender base_version: 4
Optimistisk samtidighed på en udgift. Den tabende redigering gives tilbage til sin forfatter med den version, den skal genopbygges på. Den vindende redigering når hovedbogen som en tilbageførsel plus en genbogføring, aldrig en opdatering.

Idempotens og samtidighed holdes bevidst adskilt. Indsættelsen af revisionen kører før versionskontrollen, fordi en genforsøgt redigering bærer den basisversion, den oprindeligt læste, som nu er forældet. Et genafspil skal læses som et genafspil frem for en konflikt, så revision_id svarer først og returnerer det gemte resultat.

Svaret bærer allerede det, den næste redigering har brug for

At kræve flere felter på en PATCH er kun rimeligt, hvis en klient kan få dem billigt. Hvert udgiftssvar bærer version, så en klient, der netop har skrevet en udgift, kan redigere den uden en anden læsning. Oprettelsessvaret, ændringssvaret og hver række i listen bærer det samme felt.

For den klient, der ikke netop har skrevet udgiften, returnerer GET /v1/groups/{id}/expenses/{id} versionen, de beregnede andele og de inputs, der ligger bag dem. Disse inputs kommer tilbage under de samme navne, som en PATCH accepterer: participants, split_type, percents, weights, shares, items, pools. En klient læser én form og sender den tilbage med redigeringer i stedet for at oversætte mellem to ordforråd for én regning.

GET-svaret og PATCH-forespørgslen bruger de samme feltnavne, med version omdøbt til base_version GET RETURNERER PATCH ACCEPTERER version base_version participants participants split_type split_type percents, weights, shares percents, weights, shares items, pools items, pools omdøbt
Ét ordforråd, to retninger. Kun versionsfeltet skifter navn på turen frem og tilbage, så en redigeringsklient aldrig vedligeholder et oversættelseslag mellem det, den læser, og det, den skriver.

Symmetrien betyder mest for fordelinger, der ikke kan rekonstrueres. En PERCENT-fordeling eller en specificeret regning kan ikke angives igen ud fra sine udregnede andele alene, fordi afrundingen allerede er anvendt, og basispointene og linjeposterne er væk. Revisionens øjebliksbilleder bærer også disse inputs, så historikarket kan vise, hvad der blev specificeret på enhver tidligere version.

Påkrævet nu, fordi et krav ikke kan tilføjes senere

At kræve et felt på dag ét er en beslutning om fremtiden frem for om i dag. At lempe et påkrævet felt senere er bagudkompatibelt: klienterne sender det allerede, og serveren begynder at acceptere forespørgsler uden det. At tilføje et krav senere ødelægger hver klient, der forlod sig på den gamle standardværdi.

Så retningen bliver valgt én gang, tidligt. Dimesum kræver participants, split_type og base_version på en redigering, mens antallet af klienter stadig er lille nok til at ændre. Hvis der nogensinde findes en sikker standardværdi for redigeringer, bliver felterne valgfri, og intet, der allerede er udsendt, holder op med at virke.

Lad en redigering angive, hvad den betyder

Standardværdier hører til oprettelsen, hvor forfatteren kan se den gruppe, de siger ja til. Ved en redigering er de samme standardværdier et gæt om en gruppe, der siden har flyttet sig. Dit næste skridt: åbn dit eget læse-endpoint og tjek, at det leverer fordelingens inputs tilbage under præcis de feltnavne, dit skrive-endpoint accepterer. En klient, der skal oversætte mellem de to, vil før eller siden oversætte en af dem forkert.

Ofte stillede spørgsmål

Hvorfor kræver redigering af en delt udgift participants og split_type?

Dimesum kræver begge felter, fordi standardværdierne fra oprettelse er forkerte for en redigering. Ved oprettelse bruger Dimesum som standard alle nuværende medlemmer og en lige fordeling, hvilket passer til den gruppe, forfatteren ser på. En redigering kan lande uger senere, efter nogen er flyttet ind. At genbruge de standardværdier ville trække en ny bofælle ind i en gammel middag og flade en bevidst 70/30-fordeling af husleje ud til 50/50, uden at der vises en fejl.

Hvad sker der, når to personer redigerer den samme udgift samtidig?

Den anden redigering bliver afvist med HTTP 409 og fejlkoden stale_version. Hver PATCH bærer base_version, den version dens forfatter læste, og ændringsstien sammenligner den med den låste række. En uoverensstemmelse betyder, at udgiften har flyttet sig, så redigeringen kommer tilbage, for at dens forfatter kan anvende den igen mod den version, de nu kan se. Intet bliver flettet.

Opdaterer redigering af en udgift hovedbogsrækkerne direkte?

Nej, redigering af en udgift opdaterer aldrig en hovedbogsrække i Dimesum. En redigering bogfører to posteringer i én transaktion: en EXPENSE_REVERSAL, der ophæver den gamle version postering for postering, og derefter en EXPENSE-postering for den nye version. UPDATE og DELETE er frataget hovedbogens egen databaserolle, så en mutation er umulig selv for fejlbehæftet kode. Du ser et redigeret-mærke og et historikark.

Skal jeg lave et ekstra API-kald, før jeg redigerer en delt udgift?

Nej, en klient, der netop har skrevet udgiften, har allerede den version, en redigering har brug for. Hvert udgiftssvar bærer version, som er det, den næste PATCH sender som base_version. En klient, der ikke skrev udgiften, kalder GET /v1/groups/{id}/expenses/{id}, som returnerer versionen plus fordelingens inputs under de samme feltnavne, som en PATCH accepterer.

Hvorfor kræve participants og split_type nu i stedet for at tilføje dem senere?

At kræve et felt fra dag ét kan gøres om, og at tilføje et senere kan ikke. At lempe et påkrævet felt senere er bagudkompatibelt: klienterne sender det allerede, og serveren begynder at acceptere forespørgsler uden det. At tilføje et krav senere ødelægger hver klient, der forlod sig på den gamle standardværdi, og i et penge-API er skaden usynlig, indtil nogens saldo er forkert.