dimesum

Forsiden / Blogg / Penger

Penger

Hvorfor redigering må gjenta hele fordelingen

· 8 min lesing ·

En redigerings standardverdier er pengefeil, så Dimesum gjør participants og split_type obligatoriske på hver utgifts-PATCH, sammen med base_version som avviser en utdatert redigering i stedet for å slå den sammen.

Å rette en skrivefeil skal ikke endre hvem som skylder penger. I Dimesum angir en redigering av en delt utgift hele fordelingen på nytt. participants og split_type er påkrevd på hver PATCH, og en redigering som utelater ett av dem kommer tilbake med 400 i stedet for å fylle inn en standardverdi. Standardene ved opprettelse er alle nåværende medlemmer og en lik fordeling, som på en redigering er pengefeil.

To feil gjør poenget konkret. En romkamerat som ble med i august trekkes inn i julis middag, fordi «alle nåværende medlemmer» beregnes når redigeringen lander, ikke da utgiften ble skrevet. En bevisst 70/30-fordeling av husleien flates ut til 50/50, fordi en manglende split_type betyr EQUAL. Ingen av feilene gir en feilmelding, og begge flytter ekte penger.

Standpunktet

En redigerings standardverdier er pengefeil. En standardverdi ved opprettelse gjetter på gruppen forfatteren ser på akkurat nå. En redigering kommer senere, mot en gruppe som har flyttet seg, og den samme gjetningen omskriver stille hva folk skylder.

Standardene ved opprettelse beskriver en ny utgift, ikke en gammel

Ved opprettelse er standardene ærlige. Forfatteren ser på gruppen slik den er, og en lik fordeling på alle er det vanlige tilfellet, så Dimesum fyller inn begge. Utgiften lagrer inndataene sine, ikke bare resultatene: splits.percent_bp, splits.weight og splits.exact_minor beholder det brukeren tastet inn, slik at en senere redigering kan åpne den igjen.

En redigering er en annen handling. Den samme utgiften kan rettes uker senere, etter at en ny romkamerat har blitt med eller et spøkelsesmedlem er blitt gjort krav på. Medlemskap er et bevegelig mål, og fordelingen er det ikke. Å gjenbruke standardene ved opprettelse ber dagens gruppe svare på et spørsmål den gamle utgiften allerede har svart på.

To versjoner av samme redigering: arvede standarder endrer hver andel, mens en fordeling angitt på nytt bare endrer beskrivelsen REDIGERING ARVER STANDARDENE FRA OPPRETTELSEN REDIGERING ANGIR FORDELINGEN PÅ NYTT Husleie, 20 000 kroner, juli Husleie, 20 000 kroner, juli v1 Asha 70 %, 14 000 Bhavna 30 %, 6 000 v1 Asha 70 %, 14 000 Bhavna 30 %, 6 000 Chetan flytter inn i kollektivet i august. Chetan flytter inn i kollektivet i august. PATCH retter en skrivefeil, sender ingen fordeling. PATCH retter en skrivefeil, 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 aldri bodde her. Bare beskrivelsen ble endret.
Den samme redigeringen på ett tegn, to ganger. Å arve standardene fra opprettelsen fordeler 20 000 kroner på nytt mellom tre og belaster et medlem som ble med en måned senere; å angi fordelingen på nytt lar hver andel stå urørt.

Å nekte å gjette er ikke noe nytt her. En utgift med flere betalere må angi betalerne sine på nytt også. soleStoredPayer gjenbruker den lagrede betaleren bare når utgiften har nøyaktig én, så en redigering som tier om to betalere avvises i stedet for å bli tildelt på nytt. En redigering som ikke sier noe om betalere beholder utgiftens egen betaler, aldri personen som gjør redigeringen.

API-et avviser en redigering som ikke angir fordelingen på nytt

Gateway-sjekken kjører før noen penger beregnes. Når participants er tom eller split_type er blank, kommer forespørselen tilbake med 400 med koden invalid_expense og meldingen «an edit must restate the split: participants and split_type are required». Utgiftstjenesten gjentar regelen i validateAmend, så en kaller som når tjenesten på en annen måte møter den samme avvisningen.

Hva en opprettelse sender kontra hva en redigering må angi på nytt, på POST og PATCH /v1/groups/{id}/expenses.
FeltVed opprettelseVed en redigeringHva standardverdien ville koste
participantsValgfritt. Standard er alle nåværende medlemmerPåkrevdEt medlem som ble med etterpå havner i en gammel utgift
split_typeValgfritt. Standard er EQUALPåkrevdEn 70/30-fordeling flates ut til 50/50
payersValgfritt. Standard er forfatterenUtelatt beholder utgiftens eneste betaler; to betalere må angis på nyttRedigereren blir betaleren, og snur om på hvem som skylder hvem
base_versionSendes ikkePåkrevd, og må være lik den gjeldende versjonenEn utdatert redigering overskriver en endring forfatteren aldri leste
revision_idKlient-UUIDv7, idempotensnøkkelenSamme, én per versjonEn redigering som prøves på nytt belaster gruppen to ganger
currencyOppgitt per utgiftMå stemme; en endring avvisesEn saldorad holder én valuta per medlem

Valuta hører til den samme familien av avvisninger. En redigering kan ikke omregne en utgift til en annen valuta, fordi en saldorad holder én valuta per medlem. Skrivesiden avviser endringen, og det append-only-baserte regnskapet parkerer en slik endring hvis en noen gang skulle nå det. Å avvise ved døren hindrer de to halvdelene i å være uenige.

En utdatert redigering avvises for forfatteren, aldri slått sammen

base_version er den andre halvdelen av kontrakten. Hver PATCH bærer versjonen forfatteren leste, og checkTransition sammenligner den mot raden transaksjonen nettopp låste. Lik, og redigeringen brukes på versjon pluss én. Ulik, og kalleren får HTTP 409 med koden stale_version.

Sammenslåing er det fristende alternativet, og det er feil. To redigeringer av én utgift er to fullstendige utsagn om hva regningen betyr. Å slå dem sammen gir et tredje utsagn ingen skrev, med andeler ingen av forfatterne ville kjenne igjen. Avvisning gir konflikten tilbake til den ene personen som kan løse den.

To forfattere leser versjon 3; den første redigeringen posterer versjon 4 og den andre avvises med 409 stale_version utgift, versjon 3 Forfatter A PATCH base_version: 3 200 OK, versjon 4 Forfatter B PATCH base_version: 3 409 stale_version Regnskap, én transaksjon: EXPENSE_REVERSAL av v3 EXPENSE v4 Forfatter B leser versjon 4 på nytt, bruker endringen på nytt, sender base_version: 4
Optimistisk samtidighet på en utgift. Den tapende redigeringen gis tilbake til forfatteren med versjonen den må bygges på nytt på. Den vinnende redigeringen når regnskapet som en reversering pluss en ny postering, aldri en oppdatering.

Idempotens og samtidighet holdes bevisst fra hverandre. Innsettingen av revisjonen kjører før versjonssjekken, fordi en redigering som prøves på nytt bærer basisversjonen den opprinnelig leste, som nå er utdatert. Et gjenspill må leses som et gjenspill og ikke en konflikt, så revision_id svarer først og returnerer det lagrede resultatet.

Svaret bærer allerede det den neste redigeringen trenger

Å kreve flere felt på en PATCH er bare rimelig hvis en klient kan få tak i dem billig. Hvert utgiftssvar bærer version, så en klient som nettopp skrev en utgift kan redigere den uten en ny lesing. Opprettelsessvaret, endringssvaret og hver rad i listen bærer det samme feltet.

For klienten som ikke nettopp skrev utgiften, returnerer GET /v1/groups/{id}/expenses/{id} versjonen, de beregnede andelene og inndataene bak dem. Inndataene kommer tilbake under de samme navnene som en PATCH godtar: participants, split_type, percents, weights, shares, items, pools. En klient leser én form og sender den tilbake med endringer, i stedet for å oversette mellom to vokabularer for én regning.

GET-svaret og PATCH-forespørselen bruker de samme feltnavnene, med version omdøpt til base_version GET RETURNERER PATCH GODTAR version base_version participants participants split_type split_type percents, weights, shares percents, weights, shares items, pools items, pools omdøpt
Ett vokabular, to retninger. Bare versjonsfeltet skifter navn gjennom rundturen, så en redigeringsklient vedlikeholder aldri et oversettelseslag mellom det den leser og det den skriver.

Symmetrien betyr mest for fordelinger som ikke kan rekonstrueres. En PERCENT-fordeling eller en spesifisert regning kan ikke angis på nytt ut fra de oppløste andelene alene, fordi avrunding allerede er brukt og basispunktene og linjepostene er borte. Revisjonsøyeblikksbildene bærer inndataene også, så historikkarket kan vise hva som var spesifisert på en hvilken som helst tidligere versjon.

Påkrevd nå, fordi et krav ikke kan legges til senere

Å kreve et felt fra dag én er en beslutning om fremtiden snarere enn om i dag. Å lempe på et påkrevd felt senere er bakoverkompatibelt: klientene sender det allerede, og serveren begynner å godta forespørsler uten det. Å legge til et krav senere bryter hver klient som stolte på den gamle standarden.

Så retningen velges én gang, tidlig. Dimesum krever participants, split_type og base_version på en redigering mens antallet klienter fortsatt er lite nok til å endres. Hvis en trygg standard for redigeringer noen gang blir funnet, blir feltene valgfrie og ingenting som allerede er sendt ut slutter å virke.

La en redigering angi på nytt hva den betyr

Standardverdier hører til opprettelsen, der forfatteren kan se gruppen de sier seg enige i. På en redigering er de samme standardene en gjetning om en gruppe som siden har flyttet seg. Ditt neste steg: åpne ditt eget lese-endepunkt og sjekk at det gir tilbake fordelingsinndataene under de nøyaktige feltnavnene skrive-endepunktet ditt godtar. En klient som må oversette mellom de to vil til slutt oversette en av dem feil.

Vanlige spørsmål

Hvorfor må jeg oppgi deltakere og fordelingstype når jeg redigerer en delt utgift?

Dimesum krever begge feltene fordi standardverdiene fra opprettelsen er feil for en redigering. Ved opprettelse bruker Dimesum som standard alle nåværende medlemmer, delt likt, noe som samsvarer med gruppen forfatteren ser på. En redigering kan komme uker senere, etter at noen har blitt med. Å gjenbruke disse standardene ville trekke en ny romkamerat inn i en gammel middag og flate en bevisst 70/30-fordeling av husleien tilbake til 50/50, uten at noen feil vises.

Hva skjer hvis to personer redigerer samme utgift samtidig?

Den andre redigeringen avvises med HTTP 409 og feilkoden stale_version. Hver PATCH bærer base_version, versjonen forfatteren leste, og endringsflyten sammenligner den mot den låste raden. Et avvik betyr at utgiften har flyttet seg, så redigeringen kommer tilbake til forfatteren for å brukes på nytt mot versjonen de nå kan se. Ingenting slås sammen.

Endrer redigering av en utgift regnskapsradene direkte?

Nei, å redigere en utgift oppdaterer aldri en regnskapsrad i Dimesum. En redigering posterer to journaler i én transaksjon: en EXPENSE_REVERSAL som opphever den gamle versjonen ledd for ledd, deretter en EXPENSE-journal for den nye versjonen. UPDATE og DELETE er trukket tilbake fra regnskapets egen databaserolle, så en endring er umulig selv for buggy kode. Du ser et redigert-merke og et historikkark.

Må jeg gjøre et ekstra API-kall før jeg redigerer en delt utgift?

Nei, en klient som nettopp skrev utgiften har allerede versjonen en redigering trenger. Hvert utgiftssvar bærer version, som er det neste PATCH sender som base_version. En klient som ikke skrev utgiften kaller GET /v1/groups/{id}/expenses/{id}, som returnerer versjonen pluss fordelingsdataene under de samme feltnavnene som en PATCH godtar.

Hvorfor kreve deltakere og fordelingstype nå i stedet for å legge dem til senere?

Å kreve et felt fra dag én er reversibelt, mens å legge til ett senere ikke er det. Å lempe på et påkrevd felt senere er bakoverkompatibelt: klientene sender det allerede, og serveren begynner å godta forespørsler uten det. Å legge til et krav senere bryter hver klient som stolte på den gamle standarden, og i et penge-API er bruddet stille helt til noens saldo er feil.