இருபது தொடர்புகள் (contacts) ஒரு CRM-இல் ஆர்க்கிவ் (archive) செய்யப்பட வேண்டியிருந்தது, ஆனால் UI ஒரு பச்சை நிற வெற்றிக் குறியீட்டை (success badge) காட்டியது, ஆனால் அந்தச் செயல் உண்மையில் எதுவும் செய்யாமல் அமைதியாக முடிந்துவிட்டது. Supabase-JS மியூட்டேஷன்களில் (mutations) error புலத்தை (field) கட்டாயமாக்கும் ஒரு TypeScript ஹெல்பர் (helper), டெவலப்பர்கள் இந்தத் தோல்வியைத் தட்டிக்கழிக்காமல் அதை எதிர்கொள்ளுமாறு இப்போது கட்டாயப்படுத்துகிறது.

Supabase-JS-ன் ரிட்டர்ன் ஷேப் (return shape) ஏன் ஒரு பொறியாகும்

Supabase-ன் JavaScript கிளையண்ட் (@supabase/supabase-js), ஒரு டேட்டாபேஸ் எழுத்து (write) நிராகரிக்கப்படும்போது எக்ஸெப்ஷன்களை (exceptions) வீசாது. அதற்குப் பதிலாக, அது { data, error } என்ற ஆப்ஜெக்ட்டுடன் பிராமிஸை (promise) தீர்க்கிறது (resolves). ஒரு Row-level security (RLS) பாலிசி, ஒரு unique-key மீறல் அல்லது வேறு ஏதேனும் கட்டுப்பாடுகள் குவரியைத் (query) தடுத்தால், data என்பது null என்று வரும் மற்றும் error-இல் டேட்டாபேஸ் செய்தி இருக்கும். அழைப்பவர் (caller) error-ஐ ஆய்வு செய்வார் என்று கிளையண்ட் கருதுகிறது; அது அழைப்பை ஒருபோதும் நிறுத்தாது (abort).

நடைமுறையில், பல கோட்பாடுகள் (codebases) இந்த அழைப்பை 'fire-and-forget' செயல்பாடாகக் கருதுகின்றன:

await supabase
  .from('contacts')
  .update({ statut: 'ancien', archived_at: now })
  .eq('id', id)

return { ok: true }

update என்பது ஒரு RLS விதியால் தடுக்கப்படும்போது, பிராமிஸ் இன்னும் தீர்க்கப்படுகிறது (resolves). டெவலப்பர் { error }-ஐ டிஸ்ட்ரக்சர் (destructure) செய்யாததால், அந்தத் தோல்வி கண்ணுக்குத் தெரியாமல் போகிறது. செயல்பாடு { ok: true } என்று திரும்புகிறது, UI வெற்றியைத் காட்டுகிறது, ஆனால் தரவு மாறாமல் அப்படியே இருக்கிறது. எந்த லாக்ஸ்களும் (logs) தோன்றாது, Sentry அலர்ட்டும் வராது, மேலும் இந்தத் தவறு (bug) பல நாட்களுக்கு அப்படியே இருக்கலாம்.

ஒரு லின்டர் (linter) மட்டும் போதாது

error பண்பு (property) புறக்கணிக்கப்படும்போது ஸ்டேடிக் அனாலிசிஸ் கருவிகள் (static analysis tools) எச்சரிக்கலாம், ஆனால் அவை ரன்டைம் ஒப்பந்தத்தை (runtime contract) அமல்படுத்த முடியாது. ஒரு டெவலப்பர் இன்னும் const _ = await … என்று எழுதி எச்சரிக்கையைச் சத்தமில்லாமல் செய்யலாம், அல்லது விதியைத் தவிர்க்க ஒரு கமெண்ட்டைச் சேர்க்கலாம். அடிப்படைப் பிரச்சனை என்னவென்றால், error-ஐக் குறிப்பிடாமலேயே ஒரு அழைப்பு வெற்றிபெற டைப் சிஸ்டம் (type system) அனுமதிக்கிறது.

mutate() ஹெல்பர்: எரர் ஹேண்ட்லிங்கை (error handling) கட்டாயமாக்குதல்

ஆசிரியர் mutate() என்று அழைக்கப்படும் ஒரு சிறிய ரேப்பரை (wrapper) உருவாக்கினார், இது ரிட்டர்ன் டைப்பின் ஷேப்பை மாற்றுகிறது. { data, error }-க்கு பதிலாக, இந்த ஹெல்பர் [data, error] என்ற டூப்பிளை (tuple) வழங்குகிறது, இதில் error என்பது ஒரு கட்டாயப் புலமாகும் (required field). இரண்டாவது உறுதியைத் தவிர்த்துவிடும் எந்தவொரு அழைப்பையும் TypeScript கம்பைல் செய்ய மறுக்கிறது.

async function mutate<T>(promise: Promise<{ data: T | null; error: any }>) {
  const { data, error } = await promise
  // Send error to Sentry immediately
  if (error) Sentry.captureException(error)
  return [data, error] as const
}

பயன்பாடு இப்போது வெளிப்படையானது:

const [result, err] = await mutate(
  supabase
    .from('contacts')
    .update({ statut: 'ancien', archived_at: now })
    .eq('id', id)
)

if (err) {
  // Handle or rethrow
  return { ok: false, message: err.message }
}
return { ok: true, data: result }

ஒரு டெவலப்பர் err-ஐப் பிடிக்க மறந்தால், TypeScript ஒரு பிழையை வெளியிடும்: “Tuple type [T, any] of length 2 has no element at index 1.” பிழை சரிசெய்யப்படும் வரை குறியீடு கம்பைல் ஆகாது. இந்த ஹெல்பர் Sentry இன்ஸ்ட்ருமென்டேஷனையும் (instrumentation) சேர்க்கிறது, இதனால் அழைப்பவர் பின்னர் அதைத் தடுத்தாலும், ஒவ்வொரு டேட்டாபேஸ் நிராகரிப்பும் லாக் செய்யப்படுவதை இது உறுதி செய்கிறது.

இதில் உள்ள ஆபத்துகள்

  • தரவு ஒருமைப்பாடு (Data integrity) – அமைதியான தோல்விகள் (Silent failures) தவறான நிலையைத் தயாரிப்புச் சூழலுக்குள் (production) நுழைய அனுமதிக்கின்றன. ஆர்க்கிவ் செய்யப்பட்ட ஒரு தொடர்பு (contact) ஆக்டிவ் லிஸ்ட்டிலிருந்து நீங்கவில்லை என்றால், அது அடுத்தடுத்த அறிக்கைகளில் (reports) தவறுகளை ஏற்படுத்தலாம்.
  • பயனர் நம்பிக்கை (User trust) – எதுவும் மாறாதபோது வெற்றி என்று கூறும் UI, நம்பிக்கையைச் சிதைக்கிறது. வாடிக்கையாளர்கள் "archived" என்று பார்ப்பார்கள், ஆனால் தேடல்களில் அந்தத் தொடர்பை மீண்டும் காண்பார்கள்.
  • டெவலப்பர் நேரம் (Developer time) – கண்ணுக்குத் தெரியாத பிழைகளைத் (phantom bugs) தேடுவது பல மணிநேரங்களைச் செலவழிக்கும். வெளிப்படையான எரர் ஹேண்ட்லிங், தோல்வி ஏற்படும் இடத்திலேயே சிக்கலை வெளிச்சத்திற்குக் கொண்டு வந்து, டீபக்கிங் (debugging) சுழற்சியைக் குறைக்கிறது.
  • செயல்பாட்டுச் செலவு (Operational cost) – அமைதியான தரவு இழப்புச் சம்பவத்தின் செலவோடு ஒப்பிடும்போது, சில கூடுதல் வரிகள் மற்றும் ஒரு சிறிய ரேப்பரைச் சேர்ப்பது மிகச் சிறிய விஷயமாகும்.

சமநிலை (The trade-off)

இந்த ஹெல்பர் குறியீட்டின் நீளத்தை (verbosity) அதிகரிக்கிறது: ஒவ்வொரு மியூட்டேஷன் அழைப்பும் இப்போது ஒரு டூப்பிளைத் திரும்பப் பெறுகிறது, மேலும் அழைப்பவர்கள் if (err) பிளாக்கை எழுத வேண்டும். சில குழுக்கள் இதை ஒரு தேவையற்ற வேலை (boilerplate noise) என்று கருதலாம், குறிப்பாக வெற்றி கிடைக்கும் என்று எதிர்பார்க்கும் எளிய CRUD செயல்பாடுகளுக்கு. இதற்குப் பதிலாகச் சொல்லப்படும் வாதம் என்னவென்றால், இந்த கூடுதல் குறியீடு ஒரு பாதுகாப்பு அரண், அது விருப்பத்தேர்வு அல்ல. தரவுத் துல்லியம் மிக முக்கியமான சூழல்களில்—CRM அமைப்புகள், நிதி, சுகாதாரம்—இந்தச் சரிபார்ப்பைக் கட்டாயப்படுத்துவது அதன் பலனைத் தரும்.

அடுத்து என்ன

எந்த விளக்கமும் இன்றி பூஜ்ஜிய வரிசைகளைத் (zero rows) திருப்பித் தரும் RLS பாலிசிகளை ஆராயும் மூன்றாவது பாகத்தை ஆசிரியர் உறுதியளித்துள்ளார். அந்தப் பாட்டர்ன் (pattern), அமைதியான எரர் (silent-error) நிகழ்வைப் போலவே, ஒரு வெற்றிகரமான குவரியின் பின்னால் தோல்விகளை மறைக்கிறது. இந்தத் தொடர், Supabase-ன் API-ன் "வதந்திகள்" (rumor) பக்கத்தை வெளிப்படுத்தவும், டெவலப்பர்களுக்கு உண்மைகளைக் கோருவதற்குத் தேவையான உறுதியான கருவிகளை வழங்கவும் முயல்கிறது.

சுருக்கம் (Takeaway): Supabase-JS-ன் வடிவமைப்பு, நீங்கள் error புலத்தைப் படிக்க நினைவில் கொள்ளாவிட்டால், ஒரு தோல்வியுற்ற எழுத்து வெற்றியைப் போலவே தோற்றமளிக்கச் செய்கிறது. error-ஐக் கட்டாயமாக்கி அதை Sentry-இல் லாக் செய்யும் ஒரு TypeScript-ஆல் உறுதிப்படுத்தப்பட்ட ஹெல்பரைத் பயன்படுத்துவதன் மூலம், நீங்கள் அமைதியான தோல்விகளைத் தெரியக்கூடிய, நடவடிக்கை எடுக்கக்கூடிய நிகழ்வுகளாக மாற்றுகிறீர்கள். குறியீட்டின் அளவிலான சிறிய அதிகரிப்பு, தரவு நம்பகத்தன்மை மற்றும் பயனர் நம்பிக்கையை உங்களுக்குத் தருகிறது—இவை எதனாலும் வழங்க முடியாத விஷயங்கள்.