Zespół techniczny Dropboxa ogłosił na swoim blogu, że silnik synchronizacji w aplikacji klienckiej dla komputerów osobistych, został przepisany w języku Rust. Jest to efekt pracy ostatnich czterech lat i nosi on nazwę kodową Nucleus. Zdaniem inżynierów oprogramowania nie należy ślepo celebrować i lobbować za przepisaniem dużych projektów programistycznych. Ponieważ w wielu przypadkach może się to okazać tragiczne w skutkach, z powodu złożoności kodu czy poza technicznych pobudek, choćby umowy z partnerami czy kwestii licencyjnych. Reimplementacja kodu źródłowego nie jest kwestią mody i było to ciężkie w wykonaniu zadanie.
Zobacz też: Microsoft pracuje nad nowym językiem programowania wzorowanym na Ruście
Architektura silnika synchronizacji nie zmieniła się, odkąd w 2008 roku opublikowali wersję beta klienta, przeznaczonego do powszechnego użytku. Użytkownik pobiera program Dropbox, ów tworzy własny katalog w którym zamieszcza się pliki, jakie zostaną wysłane do chmury, aby można było uzyskać do nich dostęp poprzez internet. Z biegiem czasu proste rozwiązanie konsumenckie, przeistoczyło się w kompleksowe zarządzanie danymi, zorganizowanych w hierarchię systemu plików, na milionach kont firmowych. W efekcie zostaje zwolnione miejsce na lokalnych komputerach, gdzie za sprawą inteligentnej synchronizacji przechowuje się tylko pliki niezbędne do danej pracy. Pozostałe dokumenty bezpiecznie spoczywają na zewnętrznych serwerach, jakich koszt nie stanowi już elementu wewnątrz firmowej infrastruktury, poza co miesięczną subskrypcją.
Poprzedni kod źródłowy silnika synchronizacji, określany jako “Sync Engine Classic”, posiadał słabości projektowe. Dały one sobie znać stopniowo, wraz ze wzrostem skali przedsięwzięcia. W praktyce okazało się, iż przyrostowe wprowadzanie poprawek i nowych funkcji, zostało pozbawione sensu, w świetle aktualnej architektury. W kontekście inżynierii oprogramowania problem synchronizacji plików jest kwestią architektury systemów rozproszonych. Aplikacje klienckie mogą długo pozostawać niepodłączone do sieci, a po ich powrocie następuje dwukierunkowa wymiana plików. Toteż spodziewać się można warunków brzegowych, w postaci wysłania żądania usunięcia starej lokalizacji na serwerze, tyle że następują wtedy problemy z siecią i nie dochodzi do skutku operacja przesłania plików. Użytkownik utraci wtedy dane. Wspomniany rodzaj sytuacji należy uwzględnić w projekcie oprogramowania.
Zobacz również: Nachodzi kamień milowy w rozwoju Redoksa, systemu w całości napisanego w Ruście
Dropbox bez względu na warunki musi pozostać niezawodny i nie ułatwia tego okoliczność, że wspierane są systemy Windows, Linux i macOS. Każde z własnymi idiosynkrazjami. Bywają wśród nich rzadkie błędy systemu plików, z racji mnogości konfiguracji sprzętowych i programowych, jakie programiści Dropboxa muszą poddawać nawet inżynierii wstecznej (w celu napisania obejścia), skoro chcą zachować opinię niezawodności. Jednakże, pomimo refaktoryzacji i systematycznego dopisywania kolejnych zmian, a także poleganiu na adnotacjach w Pythonie i dodaniu telemetrii, nie zmieniało to faktu, że “Sync Engine Classic” opiera się na archaicznej podstawie. Jest nią model danych (data model) któremu brak, choćby identyfikatora plików, ów byłby zachowywany pomiędzy krokami synchronizacji. Ponadto oprogramowanie nie było zaprojektowane z myślą o testach automatycznych, lecz polegano na zgłoszeniach błędów lub ręcznych testach. Model danych dopuszczał także możliwość obsługi zestawu danych, mimo że poprawnych to jednak o niepożądanym rezultacie, względem których ciężko byłoby napisać asertacje.
Dlaczego użyto języka Rust:
- W praktyce spostrzeżono zauważalną poprawę ergonomii. Wzrosła także wydajność względem Pythona. Rust także jest umyślnie (by design) nastawiony na poprawność napisanego kodu i w czasie kompilacji wykrywa błędy jakie na produkcji mogą skutkować problemami.
- Większość kodu działa na pojedynczym wątku, za pomocą biblioteki Futures. Jedynie niezbędne zadania zostają złożone na karb równoległych wątków. Są to pętla zdarzeń (event loop) i wejścia-wyjścia sieci. Obniżyło to złożoność projektu.
- Wątek Kontroli (Control thread) został zaprojektowany tak, aby był całkowicie deterministyczny, gdy jego dane wejściowe i decyzje dotyczące planisty są ustalone na sztywno (fixed). W warunkach testowych ich generator liczb losowych ustawia warunki siewu (seed) początkowego stanu systemu plików, możliwe zakłócenia i zadane prace dla ich silnika synchronizacji. Jeżeli dojdzie do niepowodzenia, choćby za sprawą niezgodnych sum kontrolnych, mogą każdorazowo odtworzyć błąd z oryginalnego siewu. Codziennie przetwarzają miliony scenariuszy jako warunki testowych.
- Przeprojektowano protokół klient-serwer dla większej spójności, jedno i drugie uzyskało ten sam podgląd do zdalnego systemu plików. Współdzielone pliki i foldery cechują się odtąd unikalnym globalnie identyfikatorem. Toteż aplikacja kliencka nigdy nie doświadcza duplikatów lub niezamierzonych stanów. Wreszcie pliki i foldery podlegają algorytmowi Θ(1) niezależnie od rozmiaru poddrzewa (subtree).