একজন ডেভেলপার একটি ইন্টারনাল টুলের জন্য REST API পরিবর্তন করে tRPC ব্যবহার করতে দুই সপ্তাহ ব্যয় করেছেন।

কেন এই পরিবর্তনটি গুরুত্বপূর্ণ ছিল

পুরনো স্ট্যাকটি আমাদের একটি DTO, একটি ভ্যালিডেটর এবং ফ্রন্টএন্ডের জন্য আলাদা TypeScript টাইপ বজায় রাখতে বাধ্য করত। ব্যাকএন্ডের একটি ফিল্ডের নাম পরিবর্তন করলে API তখনও 200 রিটার্ন করত, UI রেন্ডার হতে থাকত এবং বাগটি শুধুমাত্র “undefined” ভ্যালু হিসেবে প্রকাশ পেত। টিমের কেউ দেখার আগেই একজন গ্রাহক এই সমস্যাটি ধরে ফেলেন। REST কন্ট্রাক্টগুলো সমস্যাটি লুকিয়ে রেখেছিল এবং অতিরিক্ত ফাইলগুলো এমন রক্ষণাবেক্ষণের বোঝা বাড়িয়েছিল যার কোনো সুফল পাওয়া যায়নি।

REST সেটআপটি দেখতে কেমন ছিল

  • OpenAPI spec – একটি স্ট্যাটিক ফাইল যা এন্ডপয়েন্টগুলো বর্ণনা করত কিন্তু কখনোই তথ্যের মূল উৎস (source of truth) হিসেবে কাজ করত না।
  • Client SDK generation step – একটি CI জব যা একটি JavaScript র‍্যাপার তৈরি করত।
  • Postman collection – একটি শেয়ারড টেস্টিং আর্টিফ্যাক্ট যা কেউ ব্যবহার করত না।
  • Manual TypeScript interfaces – হাতে লেখা টাইপ যা সার্ভারের সাথে সিঙ্ক রাখতে হতো।

প্রতিটি API পরিবর্তনের ফলে অন্তত এই তিনটি আর্টিফ্যাক্ট, সাথে ভ্যালিডেটর এবং যেকোনো ডাউনস্ট্রিম fetch কল পরিবর্তন করতে হতো। এই প্রক্রিয়াটি ছিল ত্রুটিপূর্ণ এবং ধীরগতির।

কীভাবে tRPC কোডবেস কমিয়ে এনেছে

tRPC আলাদা কন্ট্রাক্ট ফাইলের প্রয়োজনীয়তা দূর করে। সার্ভার একটি router type এক্সপোর্ট করে; ক্লায়েন্ট সেই একই টাইপ ইমপোর্ট করে। ব্যাকএন্ডের একটি ফিল্ডের নাম পরিবর্তন করলে এডিটর তাৎক্ষণিকভাবে অমিলটি চিহ্নিত করে দেয়—কোড রান করার বা রিকোয়েস্ট ফেইল হওয়ার প্রয়োজন হয় না। ডেভেলপার নিচের বিষয়গুলো সরিয়ে ফেলেছেন:

  • OpenAPI spec ফাইল।
  • Client SDK generation step।
  • অব্যবহৃত Postman collection।
  • ম্যানুয়াল TypeScript interfaces-এর ফোল্ডার।

রিপোজিটরি আরও হালকা (leaner) হয়ে গেল এবং ডেপ্লয়মেন্টের পরিবর্তে ডেভেলপমেন্ট চলাকালীনই ফিডব্যাক পাওয়া শুরু হলো।

tRPC-এর সীমাবদ্ধতা

tRPC তখনই কাজ করে যখন উভয় প্রান্তেই TypeScript ব্যবহার করা হয়। এটি নিচের ক্ষেত্রে কার্যকর নয়:

  • একটি মোবাইল টিম যদি Swift বা Kotlin ব্যবহার করে।
  • API যদি বাহ্যিক পার্টনারদের দ্বারা ব্যবহার করতে হয়।
  • আপনার যদি একটি পাবলিক, ল্যাঙ্গুয়েজ-অ্যাগনস্টিক (language-agnostic) ইন্টারফেস প্রয়োজন হয়।

মাইগ্রেশনের জন্য আসলে যা প্রয়োজন ছিল

দুই সপ্তাহের এই প্রচেষ্টা কেবল কপি-পেস্টের চেয়ে বেশি ছিল। ডেভেলপারকে যা করতে হয়েছিল:

  • tRPC-এর ক্লায়েন্ট ফাংশন ব্যবহার করার জন্য প্রতিটি fetch কল পুনরায় লিখতে হয়েছে।
  • Error-handling লজিক সমন্বয় করতে হয়েছে।
  • যেসব UI কম্পোনেন্ট র (raw) HTTP রেসপন্সের সাথে যুক্ত লোডিং এবং রিট্রাই স্টেটের ওপর নির্ভর করত, সেগুলো আপডেট করতে হয়েছে।

শুরু করার আগে যে প্রশ্নগুলো করা উচিত

  • ফ্রন্টএন্ড এবং ব্যাকএন্ড উভয় ক্ষেত্রেই কি TypeScript ব্যবহার করা হচ্ছে? একটি শেয়ারড টাইপ সিস্টেম ছাড়া tRPC তার প্রধান সুবিধাটি হারায়।
  • উভয় পক্ষের জন্য কি একই টিম দায়ী? মালিকানার পার্থক্যের কারণে পুনরায় কন্ট্রাক্ট ড্রিপ্ট (contract drift) দেখা দিতে পারে।
  • আপনি কি কোনো নির্দিষ্ট বাগ ঠিক করছেন নাকি কেবল ট্রেন্ড অনুসরণ করছেন? প্রোডাক্টিভিটি বৃদ্ধি বাস্তব, তবে এটি বিদ্যমান কোনো সমস্যার সমাধান করার জন্য হওয়া উচিত।

২০২৫ সালের জন্য একটি হাইব্রিড পদ্ধতি

অনেক টিম উভয় স্ট্যাক ব্যবহার করে একটি ভারসাম্যপূর্ণ সমাধান খুঁজে পায়:

  • ইন্টারনাল অ্যাপ্লিকেশন লেয়ারের জন্য tRPC, যেখানে কোডবেস সম্পূর্ণভাবে TypeScript এবং একই টিম সার্ভার ও ক্লায়েন্টের মালিক।
  • Webhook, পাবলিক API এবং পার্টনার ইন্টিগ্রেশনের জন্য REST, যেখানে ল্যাঙ্গুয়েজ-অ্যাগনস্টিক অ্যাক্সেস প্রয়োজন।

প্রতিটি ক্ষেত্রে সঠিক টুল ব্যবহার করলে ইন্টারনাল ডেভেলপমেন্ট দ্রুত থাকে এবং একই সাথে বাহ্যিক ব্যবহারকারীদের জন্য প্রয়োজনীয় উন্মুক্ততা বজায় থাকে।

সারকথা: REST-এর পরিবর্তে tRPC ব্যবহার করলে ডুপ্লিকেট কন্ট্রাক্ট আর্টিফ্যাক্টগুলো দূর করা সম্ভব এবং এডিট করার সময় বাগগুলো ধরা পড়ে, তবে এই সুবিধা তখনই পাওয়া যায় যখন পুরো স্ট্যাকটি TypeScript শেয়ার করে এবং টিম মাইগ্রেশনের খরচ বহন করতে পারে। একটি মিশ্র কৌশল আপনাকে non-TypeScript ব্যবহারকারীদের বাদ না দিয়েই এর সুবিধাগুলো গ্রহণ করতে সাহায্য করে।