Files
lux/refactor.md
T
2026-06-03 11:14:10 +02:00

3.3 KiB

Refactor: VocabolarioService Traduci

Stato Attuale (pre-refactor)

  • VocabolarioService è Singleton (DataServiceCollectionExtensions:118)
  • Traduci(lingua, lemma) è un mockup che ritorna "lingua_lemma" (linea 107)
  • Codice di fallback commented-out (linee 105-125): tentava carico lazy su Dictionary statica
  • EnsureInitializedAsync() esisteva ma non veniva mai chiamato
  • DictVocab era protected static Dictionary<string,string> — non thread-safe
  • CRUD (Upsert, UpsertMany, Delete, Clone) invalidano la cache Redis con ClearCacheAsync(...)
  • ListLingueAsync, GetAllAsync, GetByLang usano tutti GetOrSetCacheAsync su Redis

Progettazione

Obiettivo: Traduci() sincrona, rapidissima (dizionario in-memory), con invalidazione su cambio vocabolario.

Scelte:

  1. Niente static — rimuovo protected static DictVocab. Il servizio è già Singleton, quindi un'istanza per processo è sufficiente. Elimino rischi di leak in test/iniezione.

  2. ConcurrentDictionary<string, Dictionary<string, string>> — struttura a due livelli: Lingua -> Dictionary<Lemma, Traduzione>. Lookup 0 allocations. Blazor Server usa circuiti concorrenti, quindi ConcurrentDictionary è sicuro per consultazione.

  3. Lazy loading con single-check + SemaphoreSlim — primo caricamento lazy sulla prima chiamata a Traduci(). Dopo, il dizionario è sempre popolato.

  4. Invalidazione sincrona dopo CRUD — ogni metodo CRUD che modifica i dati richiama _syncDictFromRepo() dopo ClearCacheAsync(). Questo mantiene coerenza tra Redis-cache e dizionario in-memory.

  5. Fallback silenzioso — se una lingua o lemma non esiste, ritorno il lemma stesso (standard i18n: "untranslated → use key"). Se il load dal DB fallisce, resto con lo stato precedente — non interrompo il flusso.

Modifiche ESEGUITE

VocabolarioService.cs

Rimosso:

  • protected static Dictionary<string, string> DictVocab — campo statico non thread-safe e mai utilizzato
  • EnsureInitializedAsync() — metodo morto, mai chiamato

Aggiunto:

  • _translations: ConcurrentDictionary<string, Dictionary<string, string>> — dizionario a doppia chiave (Lingua → Lemma → Traduzione), case-insensitive su entrambi i livelli
  • _initLock: SemaphoreSlim — lock per caricamento lazy thread-safe
  • _initialized: bool — flag single-check
  • _syncDictFromRepo() — metodo private sincrono post-CRUD, ricariche il dizionario completo dal repo
  • Cambiato il pattern: ogni CRUD (CloneAsync, DeleteAsync, UpsertAsync, UpsertManyAsync) ora chiama _syncDictFromRepo() dopo ClearCacheAsync()
  • Implementato Traduci() — prima chiamata a Traduci()EnsureDictLoaded() che fa lazy-load dal repo; dopo quella.lookup diretta su _translations[lingua][lemma]; fallback → lemma
  • Nuovo LoadDictFromRepoAsync() — query _repo.GetAllAsync(), costruisce il ConcurrentDictionary a due livelli

IVocabolarioService.cs

Nessuna modifica — mantenuta la stessa interfaccia. Traduci rimane sync con stessa signature.

Altri file

Nessuna modifica necessitata:

  • Repository: nessun cambiamento
  • DI Registration DataServiceCollectionExtensions: nessun cambiamento
  • DI Registration UI Program.cs: nessun cambiamento
  • NavMenu.razor / .razor.cs: nessun cambiamento, usa Traduci() come prima
  • Vocabulary.razor: nessun cambiamento