Ostatni zapis nie zawsze oznacza prawidłowy wynik
Wyobraź sobie dwie osoby otwierające kartę klienta. Pierwsza poprawia numer telefonu, a druga dopisuje opiekuna. Jeżeli obie wysyłają cały formularz, druga może przywrócić stary telefon, mimo że wcale go nie dotykała. Każda zobaczy komunikat sukcesu, a zespół straci poprawkę. Nie jest to błąd szybkości internetu, lecz brak reguły rozstrzygania równoczesnych zmian. Przed wyborem rozwiązania ustal, które informacje wolno łączyć, a które wymagają wspólnej decyzji.
W przykładzie z adresem samo połączenie różnych pól także może być niebezpieczne. Jedna osoba zmienia miasto, druga kod pocztowy na podstawie starego miejsca. Automatyczne scalenie da nową, lecz niespójną całość. Traktuj adres, warunki umowy i inne zależne wartości jako logiczne grupy. Ochrona przed utratą zapisu ma zachować sens danych, nie tylko dowieść, że żaden znak nie zniknął. Dlatego analiza zaczyna się od procesu pracy, nie od dodatkowej ikonki w formularzu.
Rekord potrzebuje wersji znanej w chwili otwarcia
Przy odczycie dołącz numer wersji rekordu. Przy zapisie serwer powinien atomowo sprawdzić, czy nadal jest to ta sama wersja, i dopiero wtedy wykonać zmianę oraz zwiększyć licznik. Osobne sprawdzenie, a następnie bezwarunkowy zapis zostawia lukę na kolejną zmianę między tymi operacjami. Jeżeli aktualizacja nie objęła żadnego wiersza, aplikacja musi rozróżnić konflikt, brak rekordu i brak uprawnień, zamiast uznać wszystko za sukces.
W interfejsie HTTP podobną rolę może pełnić warunek If-Match oparty na identyfikatorze wersji zasobu. Sam znacznik wysłany przez przeglądarkę niczego jednak nie zabezpiecza, jeżeli backend go ignoruje. Numer wersji nie zastępuje kontroli dostępu ani walidacji. Przy każdym zapisie nadal sprawdzasz, kto zmienia jakie pola. Zegar urządzenia klienta nie jest dobrym arbitrem kolejności, ponieważ może być błędnie ustawiony lub celowo zmieniony.
Pokaż konflikt bez kasowania wpisanej pracy
Ekran konfliktu powinien zachować tekst pracownika i wskazać, co zmieniło się na serwerze od chwili otwarcia. Przydatne są trzy wartości: pierwotna, aktualna oraz proponowana przez użytkownika. Bez wartości pierwotnej trudno odróżnić świadomą zmianę od pola, które tylko wróciło w pełnym formularzu. Nie odświeżaj automatycznie całego widoku w sposób usuwający niezapisane notatki. Komunikat ma umożliwić decyzję, nie jedynie ogłosić porażkę.
Dla niezależnych pól można zaproponować scalenie, ale pokaż jego rezultat przed zatwierdzeniem. Dla statusu sprawy lub kwoty zobowiązania lepsza może być ponowna ocena aktualnego rekordu. Przycisk „Nadpisz wszystko” jest ryzykownym skrótem, szczególnie jeśli dostępny bez dodatkowego wyjaśnienia. Gdy użytkownik zatwierdza rozwiązanie konfliktu, zapis znów powinien być warunkowy. W czasie czytania komunikatu ktoś trzeci mógł już dokonać kolejnej zmiany.
Informacja o obecności nie jest blokadą danych
Komunikat „Anna ogląda ten rekord” może ułatwić współpracę, ale nie gwarantuje wyłączności edycji. Karta mogła zostać uśpiona, urządzenie utraciło sieć albo użytkownik otworzył drugi formularz. Traktuj obecność jako pomoc organizacyjną. Twarda blokada na czas edycji wymaga z kolei wygasania, odnowienia i sposobu obsługi porzuconej sesji. Bez tych reguł karta klienta może pozostać niedostępna po zamknięciu laptopa.
Nie utrzymuj transakcji bazodanowej przez cały czas, gdy człowiek wypełnia formularz. Długi czas blokowania może utrudniać pracę innym procesom. Dla typowej karty CRM rozsądnym punktem wyjścia jest krótki, warunkowy zapis i czytelny konflikt. Wyjątki, na przykład wydanie niepodzielnego zasobu, wymagają odrębnego modelu transakcyjnego. Wybór powinien wynikać ze znaczenia operacji, a nie z chęci zastosowania identycznego mechanizmu do każdego pola w systemie.
Dziennik zmian powinien wyjaśniać decyzję
Zapisz autora, czas serwera, zmienione pola oraz wersję wejściową i wynikową. Przy operacjach wrażliwych przydatny bywa powód korekty. Nie kopiuj przy tym do logu sekretów ani całych dokumentów bez potrzeby. Rejestr powinien pozwalać ustalić, dlaczego telefon klienta wrócił do starej wartości, a nie tworzyć dodatkową niekontrolowaną bazę wszystkich danych. Dostęp do historii wymaga takich samych przemyślanych zasad jak dostęp do rekordu.
Oddziel poprawienie błędu od cofnięcia zmian. Przywrócenie starej wersji całego klienta może usunąć późniejsze, prawidłowe informacje. Bezpieczniej często utworzyć nową korektę wybranych pól na bazie aktualnego stanu. Historia pozostaje wtedy ciągła. Użytkownik widzi, że zmiana została skorygowana, zamiast oglądać pozornie niezmieniony rekord. Takie podejście ułatwia także rozmowę z osobą, która podjęła decyzję na podstawie wcześniejszej informacji.
Przetestuj kolizję świadomie, nie czekaj na zgłoszenie
Otwórz ten sam rekord w dwóch niezależnych sesjach. Zmień najpierw różne pola, potem to samo pole, następnie logicznie powiązane wartości. Sprawdź usunięcie rekordu podczas edycji, odebranie uprawnień i zapis po długiej przerwie. Próba tylko jednego użytkownika nie weryfikuje ochrony współbieżności. Potrzebny jest scenariusz, w którym oba formularze naprawdę zaczynają z tej samej wersji, a serwer musi odrzucić lub bezpiecznie rozstrzygnąć drugi zapis.
Odbierz także zachowanie interfejsu: czy da się skopiować własną notatkę, przejść klawiaturą przez porównanie i ponowić zapis bez utraty danych. Zliczaj konflikty według typu operacji. Ich duża liczba może wskazywać na zbyt szeroki formularz, nie na nieuważnych pracowników. Rozdzielenie niezależnych zadań bywa lepsze niż coraz bardziej skomplikowane scalanie. Dobrze zaprojektowany CRM pozwala współpracować, ale nie udaje, że sprzeczne decyzje nigdy się nie zdarzają.
