নিরাপদ কাস্টম মিডলওয়্যার সহ রপ্তানি করা Go ব্যাকএন্ড বাড়ান
রপ্তানি করা Go ব্যাকএন্ডে কাস্টম কোড যোগ করার নিরাপদ উপায়: কোথায় কাস্টম কোড রাখবেন, কিভাবে মিডলওয়্যার ও এন্ডপয়েন্ট যোগ করবেন, এবং আপগ্রেডের পরিকল্পনা করবেন কিভাবে।

রপ্তানি করা কোড কাস্টমাইজ করলে কোথায় সমস্যা হয়
রপ্তানি করা কোডটি একেবারেই হাতে লেখা Go রেপো নয়। AppMaster-এর মতো প্ল্যাটফর্মে ব্যাকএন্ড ভিজ্যুয়াল মডেল (ডাটা স্কিমা, ব্যবসায়িক প্রক্রিয়া, API সেটআপ) থেকে জেনারেট করা হয়। যখন আপনি পুনরায় রপ্তানি করবেন, জেনারেটর আপডেট হওয়া মডেলের সাথে মিলিয়ে বড় অংশ কোড পুনঃলিখে দিতে পারে। এটা কোডকে পরিষ্কার রাখার জন্য ভালো, কিন্তু কাস্টমাইজ করার ধরন বদলে দেয়।
সবচেয়ে সাধারণ ভুল হল জেনারেট করা ফাইলগুলো সরাসরি এডিট করা। একবার কাজ করে, পরের রপ্তানিতে আপনার পরিবর্তন ওভাররাইট হয়ে যায় বা জটিল মার্জ কনফ্লিক্ট তৈরি হয়। এমনকি ছোট ম্যানুয়াল এডিটগুলো জেনারেটরের কিছু অনুমানে (রাউটিং অর্ডার, মিডলওয়্যার চেইন, রিকোয়েস্ট ভ্যালিডেশন) চুপচাপ ভাঙনও আনতে পারে। অ্যাপ এখনও বিল্ড হওয়ায় আচরণ বদলে যেতে পারে।
নিরাপদ কাস্টমাইজেশন মানে আপনার পরিবর্তনগুলো পুনরাবৃত্তিযোগ্য এবং রিভিউ করার জন্য সহজ হওয়া। যদি আপনি ব্যাকএন্ড পুনরায় রপ্তানি করতে পারেন, আপনার কাস্টম স্তর প্রয়োগ করতে পারেন এবং স্পষ্টভাবে দেখতে পান কি পরিবর্তন হয়েছে — তাহলে আপনি ভালো পথে আছেন। যদি প্রতি আপগ্রেডেই খননকাজ মনে হয়, আপনি ভালো অবস্থায় নেই।
ভুল জায়গায় কাস্টমাইজ করলে সাধারণত দেখা যাওয়া সমস্যাগুলো:
- আপনার এডিটগুলো রপ্তানির পরে বাদ যায়, অথবা আপনাকে ঘণ্টার পর ঘণ্টা কনফ্লিক্ট রেজল্ভ করতে হয়।
- রাউটগুলো সরে যায় এবং আপনার মিডলওয়্যার আর প্রত্যাশিত স্থানে কাজ করে না।
- লজিক ডুপ্লিকেট হয়ে যায় — এক অংশ নো-কোড মডেলে এবং আরেকটি অংশ Go কোডে — ও পরে ড্রিফট শুরু হয়।
- একটি “এক-লাইন” পরিবর্তন এমন একটি ফর্কে পরিণত হয় যা কেউ ছেড়ে দেখতে চায় না।
একটি সহজ নিয়ম আপনাকে সিদ্ধান্ত নিতে সাহায্য করবে: যদি পরিবর্তনটি এমন কি যা নন-ডেভেলপাররাও সামঞ্জস্য করতে সক্ষম হওয়া উচিত (ফিল্ড, ভ্যালিডেশন, ওয়ার্কফ্লো, পারমিশন), তা নো-কোড মডেলে রাখুন। যদি এটি ইনফ্রাস্ট্রাকচারস সংক্রান্ত (কাস্টম অথ ইন্টেগ্রেশন, রিকোয়েস্ট লগিং, বিশেষ হেডার, রেট লিমিট), তাহলে এটিকে এমন কাস্টম Go স্তরে রাখুন যা রি-এক্সপোর্ট টিকে টিকে যায়।
উদাহরণ: প্রতি রিকোয়েস্টের জন্য অডিট লগিং সাধারণত মিডলওয়্যার-এ রাখা উচিত (কাস্টম কোড)। একটি অর্ডারের নতুন আবশ্যক ফিল্ড সাধারণত ডেটা মডেলে থাকে (নো-কোড)। এই বিভাজন পরিষ্কার রাখুন, তাহলে আপগ্রেড voorspelbaar থাকবে।
কোডবেস ম্যাপ করুন: জেনারেটেড অংশ বনাম আপনার অংশ
রপ্তানি করা ব্যাকএন্ড বাড়ানোর আগে ২০ মিনিট ব্যয় করে ম্যাপ করুন কোন অংশ পুনরায় জেনারেট হবে এবং কোন অংশ আপনার মালিকানাধীন। ওই মানচিত্রটিই আপগ্রেডকে সহজ রাখবে।
জেনারেটেড কোড প্রায়ই নিজেই নিজেকে প্রকাশ করে: হেডার কমেন্টে "Code generated" বা "DO NOT EDIT" লেখা, ধারাবাহিক নামকরণ প্যাটার্ন, এবং খুবই ইউনিফর্ম স্ট্রাকচার যেখানে কম মানবীয় মন্তব্য থাকে।
একটি ব্যবহারিক শ্রেণীবিভাজন তিনটি বাকেট-এ ভাগ করা যেতে পারে:
- Generated (read-only): যেখানে স্পষ্ট জেনারেটর মার্কার আছে, পুনরাবৃত্তি প্যাটার্ন আছে, বা ফোল্ডারগুলো ফ্রেমওয়ার্ক স্কেলেটনের মত।
- Owned by you: আপনি যে প্যাকেজগুলো তৈরি করেছেন, র্যাপার এবং কনফিগারেশন যা আপনি নিয়ন্ত্রণ করেন।
- Shared seams: রাউট, মিডলওয়্যার, হুক নিবন্ধনের মতো ওয়্যারিং পয়েন্ট — যেখানে ছোট এডিট দরকার হতে পারে কিন্তু তা ছোট রাখা উচিত।
প্রথম বাকেটটিকে রিড-ওনলি হিসেবে ট্রিট করুন, এমনকি আপনি টেকনিক্যালি এটিকে এডিট করতে পারেন। যদি আপনি এটিকে পরিবর্তন করেন, ধরে নিন জেনারেটর পরে ওভাররাইট করবে বা আপনি চিরদিন মার্জ বোঝা বহন করবেন।
টিমের জন্য সীমানাটি বাস্তব করে তুলুন একটি ছোট নোট লিখে এবং রেপোতে রাখুন (উদাহরণস্বরূপ, রুট README)। সহজ ভাষায় লিখুন:
"Generator-owned files: anything with a DO NOT EDIT header and folders X/Y. Our code lives under internal/custom (or similar). Only touch wiring points A/B, and keep changes there small. Any wiring edit needs a comment explaining why it can't live in our own package."
ওই এক নোট দ্রুত ফিক্সগুলোকে স্থায়ী আপগ্রেড সমস্যায় পরিণত হওয়া থেকে রুখে দেয়।
কাস্টম কোড কোথায় রাখবেন যাতে আপগ্রেড সহজ থাকে
সবচেয়ে নিরাপদ নিয়মটি সহজ: রপ্তানি করা কোডকে রিড-ওনলি হিসেবে বিবেচনা করুন এবং আপনার পরিবর্তনগুলো স্পষ্টভাবে মালিকানাধীন কাস্টম এলাকায় রাখুন। যখন আপনি পরে পুনরায় রপ্তানি করবেন, আপনি চান মার্জ হয়ে বেশিরভাগ জেনারেটেড কোড বদলে যাবে কিন্তু আপনার কাস্টম কোড অক্ষত থাকবে।
একটি পৃথক প্যাকেজ তৈরি করুন আপনার অতিরিক্তের জন্য। এটি রেপোর ভিতরে থাকতে পারে, কিন্তু জেনারেটেড প্যাকেজগুলোর মধ্যে মিশে থাকা উচিত নয়। জেনারেটেড কোড কোর অ্যাপ চালায়; আপনার প্যাকেজ মিডলওয়্যার, রাউট এবং হেল্পার যোগ করে।
একটি ব্যবহারিক লেআউট:
internal/custom/— মিডলওয়্যার, হ্যান্ডলার এবং ছোট হেল্পারদের জন্যinternal/custom/routes.go— কাস্টম রুট এক জায়গায় রেজিস্টার করার জন্যinternal/custom/middleware/— রিকোয়েস্ট/রেসপন্স লজিকের জন্যinternal/custom/README.md— ভবিষ্যৎ এডিটের জন্য কিছু নিয়ম
সার্ভারের ওয়্যারিং পাঁচটা জায়গায় এডিট করা থেকে বিরত থাকুন। একটি পাতলা "হুক পয়েন্ট" লক্ষ্য করুন যেখানে আপনি মিডলওয়্যার লাগাবেন এবং অতিরিক্ত রুট নিবন্ধন করবেন। যদি জেনারেটেড সার্ভার রাউটার বা হ্যান্ডলার চেইন এক্সপোজ করে, সেখানে প্লাগ ইন করুন। যদি না করে, এন্ট্রিপয়েন্টের কাছে একটি একক ইন্টিগ্রেশন ফাইল যোগ করুন যা custom.Register(router) মতো কিছু কল করে।
কাস্টম কোডটি এমনভাবে লিখুন যেন আপনি এটিকে আগামী রপ্তানিতে নতুন এক্সপোর্টে ড্রপ করতে পারেন। ডিপেন্ডেন্সি কম রাখুন, যেখানে সম্ভব জেনারেটেড টাইপ কপি করা এড়ান, এবং ছোট অ্যাডাপ্টার ব্যবহার করুন।
ধাপে ধাপে: কাস্টম মিডলওয়্যার নিরাপদে যোগ করা
লক্ষ্য হচ্ছে লজিক আপনার নিজের প্যাকেজে রাখা এবং জেনারেটেড কোডকে খুবই সীমিত এক স্থানে স্পর্শ করা।
প্রথমত, মিডলওয়্যারটি সংকীর্ণ রাখুন: রিকোয়েস্ট লগিং, সহজ অথ চেক, একটি রেট লিমিট, বা রিকোয়েস্ট আইডি। এটি যদি তিনটি কাজ করতে চেষ্ট করে, পরে আপনি আরো ফাইল পরিবর্তন করতে বাধ্য হবেন।
একটি ছোট প্যাকেজ বানান (উদাহরণ: internal/custom/middleware) যা পুরো অ্যাপটিকে জানার প্রয়োজন নেই। পাবলিক সারফেস ছোট রাখুন: একটি কনস্ট্রাকটর ফাংশন যা একটি স্ট্যান্ডার্ড Go হ্যান্ডলার র্যাপার রিটার্ন করে।
package middleware
import "net/http"
func RequestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Add header, log, or attach to context here.
next.ServeHTTP(w, r)
})
}
এখন একটি একক ইন্টিগ্রেশন পয়েন্ট বাছুন: যেখানে রাউটার বা HTTP সার্ভার তৈরি হয়। আপনার মিডলওয়্যার সেখানে একবার রেজিস্টার করুন এবং পৃথক রুটে ছড়িয়ে পরিবর্তন করতে এড়িয়ে চলুন।
ভেরিফিকেশন লুপটি ছোট রাখুন:
httptestব্যবহার করে একটি ফোকাসড টেস্ট যোগ করুন যা একটি আউটকাম (স্ট্যাটাস কোড বা হেডার) চেক করে।- একবার ম্যানুয়ালি রিকোয়েস্ট করে আচরণ নিশ্চিত করুন।
- যাচাই করুন মিডলওয়্যার এরর অবস্থায় যুক্তিসঙ্গতভাবে আচরণ করে।
- রেজিস্ট্রেশন লাইনের পাশে ছোট মন্তব্য যোগ করুন কেন এটি আছে।
ছোট ডিফ, এক ওয়্যারিং পয়েন্ট, সহজ রি-এক্সপোর্ট।
ধাপে ধাপে: নতুন এন্ডপয়েন্ট যোগ করা ছাড়া সবকিছু ফর্ক না করা
জেনারেটেড কোডকে রিড-ওনলি বিবেচনা করে আপনার এন্ডপয়েন্টটি ছোট কাস্টম প্যাকেজে যোগ করুন যা অ্যাপ ইমপোর্ট করে। এটাই আপগ্রেডকে যুক্তিসঙ্গত রাখে।
শুরুতে কন্ট্রাক্ট লেখে নিন, তারপর কোডে টাচ করুন। এন্ডপয়েন্ট কি গ্রহণ করবে (কোয়েরি প্যারাম, JSON বডি, হেডার)? কি রিটার্ন করবে (JSON শেপ)? স্ট্যাটাস কোডগুলো আগে থেকে চয়ন করুন যাতে পরে “যা কাজ করেছে” আচরণ না হয়।
আপনার কাস্টম প্যাকেজে একটি হ্যান্ডলার তৈরি করুন। একেবারে সাধারণ রাখুন: ইনপুট পড়ুন, ভ্যালিডেট, বিদ্যমান সার্ভিস বা ডিবি হেল্পার কল করুন, রেসপন্স লিখুন।
রাউট নিবন্ধন করুন একই একক ইন্টিগ্রেশন পয়েন্টে যেখান থেকে আপনি মিডলওয়্যার নিবন্ধন করেন, জেনারেটেড হ্যান্ডলার ফাইলগুলোর ভিতরে নয়। স্টার্টআপের সময় রাউটার কোথায় অ্যাসেম্বল হয় সেখানে আপনার কাস্টম রুট মাউন্ট করুন। যদি জেনারেটেড প্রজেক্টে ইউজার হুক বা কাস্টম রেজিস্ট্রেশন সাপোর্ট থাকে, সেটা ব্যবহার করুন।
একটি সংক্ষিপ্ত চেকলিস্ট আচরণ ধারাবাহিক রাখে:
- ইনপুট দ্রুত ভ্যালিডেট করুন (অবশ্যকীয় ফিল্ড, ফরম্যাট, min/max)।
- সর্বত্র একটি একরকম এরর শেপ রিটার্ন করুন (message, code, details)।
- যেখানে কাজ আটকে যেতে পারে সেখানে context timeout ব্যবহার করুন (DB, নেটওয়ার্ক কল)।
- অনাকাঙ্ক্ষিত এররগুলো একবার লগ করুন, তারপর ক্লিন 500 রিটার্ন করুন।
- নতুন রুট টির জন্য একটি ছোট টেস্ট যোগ করুন যা স্ট্যাটাস ও JSON চেক করে।
এছাড়াও নিশ্চিত করুন রাউটার আপনার এন্ডপয়েন্ট ঠিক একবার রেজিস্টার করে। ডুপ্লিকেট রেজিস্ট্রেশন একটি সাধারণ পোস্ট-মার্জ জালতা।
এমন ইন্টিগ্রেশন প্যাটার্ন যা পরিবর্তন সীমাবদ্ধ রাখে
জেনারেটেড ব্যাকএন্ডকে একটি ডিপেন্ডেন্সি হিসেবে ট্রিট করুন। রচনা (composition) প্রাধান্য দিন: জেনারেটেড অ্যাপের চারপাশে ফিচারগুলো ওয়্যার করুন পরিবর্তে তার কোর লজিক এডিট করার।
কনফিগারেশন ও কম্পোজিশনকে প্রাধান্য দিন
কোড লেখার আগে দেখুন আচরণ কনফিগারেশন, হুক বা স্ট্যান্ডার্ড কম্পোজিশন দিয়ে যোগ করা যাবে কি না। মিডলওয়্যার একটি ভাল উদাহরণ: এটাকে এজে (রাউটার/HTTP স্ট্যাক) যোগ করুন যাতে সেটা সরিয়ে ফেলা বা পুনঃঅর্ডার করা সহজ হয়।
যদি নতুন আচরণ দরকার (রেট লিমিটিং, অডিট লগিং, রিকোয়েস্ট আইডি), সেটি আপনার নিজস্ব প্যাকেজে রাখুন এবং একটি একক ইন্টিগ্রেশন ফাইল থেকে রেজিস্টার করুন। রিভিউতে এটা সহজে বোঝানো যাবে: “one new package, one registration point.”
অ্যাডাপ্টার ব্যবহার করে জেনারেটেড টাইপ লিক করা এড়ান
জেনারেটেড মডেল ও DTO গুলো রপ্তানির সাথে বদলে যেতে পারে। আপগ্রেড ব্যথা কমাতে, সীমানায় ট্রান্সলেট করুন:
- জেনারেটেড রিকোয়েস্ট টাইপগুলোকে আপনার নিজের ইন্টারনাল স্ট্রাক্টে কনভার্ট করুন।
- ডোমেইন লজিক শুধু আপনার স্ট্রাক্টে চালান।
- রেজাল্টগুলো আবার জেনারেটেড রেসপন্স টাইপে কনভার্ট করুন।
এইভাবে, যদি জেনারেটেড টাইপ বদলে যায়, কম্পাইলার আপনাকে এক জায়গায় আপডেট করতে বলে।
যখনই সত্যিই জেনারেটেড কোড স্পর্শ করতে হয়, একটিই ওয়্যারিং ফাইলে তা সীমাবদ্ধ রাখুন। অনেক জেনারেটেড হ্যান্ডলারে এডিট ছড়িয়ে দেবেন না।
// internal/integrations/http.go
func RegisterCustom(r *mux.Router) {
r.Use(RequestIDMiddleware)
r.Use(AuditLogMiddleware)
}
একটি ব্যবহারিক নিয়ম: যদি আপনি 2-3 বাক্যে পরিবর্তনটি ব্যাখ্যা করতে না পারেন, তাহলে সেটি সম্ভবত অত্যন্ত জড়িত।
সময়ের সাথে ডিফ কিভাবে ম্যানেজ করবেন
লক্ষ্য হচ্ছে একটি রি-এক্সপোর্ট সপ্তাহব্যাপী কনফ্লিক্টে পরিণত না হওয়া। এডিটগুলো ছোট, সহজে খুঁজে পাওয়া যায় এবং ব্যাখ্যা যোগ্য রাখুন।
শুরু থেকেই Git ব্যবহার করুন এবং জেনারেটেড আপডেটগুলো আপনার কাস্টম কাজ থেকে আলাদা রাখুন। যদি আপনি মিশিয়ে রাখেন, পরে বোঝা যাবে না কোনটা বাগের কারণ।
একটি কমিট রুটিন যা পড়তে সহজ থাকে:
- প্রতিটি কমিটের একটি উদ্দেশ্য রাখুন ("Add request ID middleware", না যে "misc fixes").
- ফরম্যাটিং-শুধু পরিবর্তনগুলো লজিক বদলের সঙ্গে মিশাবেন না।
- প্রতিটি রি-এক্সপোর্টের পরে প্রথমে জেনারেটেড আপডেট কমিট করুন, তারপর আপনার কাস্টম সমন্বয়গুলো কমিট করুন।
- কোন প্যাকেজ বা ফাইল আপনি স্পর্শ করেছেন সেটা উল্লেখ করে কমিট মেসেজ রাখুন।
একটি সহজ CHANGELOG_CUSTOM.md রেখে দিন যাতে প্রতিটি কাস্টোমাইজেশনের সংক্ষিপ্ত বিবরণ, কেন সেটি আছে, এবং কোথায় আছে লেখা থাকে। AppMaster এক্সপোর্টের ক্ষেত্রে এটা বিশেষভাবে দরকারী, কারণ প্ল্যাটফর্ম পুরো কোড পুনরায় জেনারেট করতে পারে এবং আপনি দ্রুত জানতে চাইবেন কি পুনরায় প্রয়োগ বা পুনঃভেরিফাই করা উচিত।
ডিফের শব্দ কমাতে কনসিস্টেন্ট ফরম্যাটিং ও লিন্ট রুল চালান। প্রতিটি কমিটে gofmt চালান এবং CI-তে একই চেকগুলো চালান। যদি জেনারেটেড কোড কোনো নির্দিষ্ট স্টাইল ব্যবহার করে, হাতে করে সেটা "পরিষ্কার" করে দিতে যাবেন না যদি না আপনি প্রতিটি রি-এক্সপোর্টের পরে সেই ক্লিনআপ পুনরায় করতে প্রস্তুত থাকেন।
যদি আপনার টিম প্রতি রপ্তানির পরে একই ম্যানুয়াল এডিটগুলো বারবার করে, তাহলে একটি প্যাচ ওয়ার্কফ্লো বিবেচনা করুন: রপ্তানি, প্যাচ প্রয়োগ (বা স্ক্রিপ্ট), টেস্ট চালান, ডিপ্লয়।
আপগ্রেড পরিকল্পনা: রি-এক্সপোর্ট, মার্জ এবং ভেরিফাই
আপগ্রেডগুলো সবচেয়ে সহজ হয় যখন আপনি ব্যাকএন্ডকে এমন কিছু হিসেবে আচরণ করেন যা আপনি পুনরায় জেনারেট করতে পারেন, না যে আপনি চিরস্থায়ীভাবে হস্তনির্মিতভাবে রক্ষণাবেক্ষণ করছেন। লক্ষ্যটি হল: পরিষ্কারভাবে রি-এক্সপোর্ট করুন, তারপর প্রতিটি সময় একই ইন্টিগ্রেশন পয়েন্টগুলো দিয়ে আপনার কাস্টম আচরণ পুনরায় প্রয়োগ করুন।
আপনার রিস্ক টলারেন্স এবং অ্যাপ কত ঘন ঘন বদলায় তার উপর ভিত্তি করে একটি আপগ্রেড রিদম বেছে নিন:
- প্ল্যাটফর্ম রিলিজ অনুযায়ী যদি নিরাপত্তার ফিক্স বা নতুন ফিচার দরকার হয় দ্রুত
- কোয়ার্টারলি যদি অ্যাপ স্থিতিশীল এবং পরিবর্তন ক্ষুদ্র হয়
- শুধুমাত্র প্রয়োজন হলে যদি ব্যাকএন্ড খুব কমই বদলে এবং টিম ছোট হয়
আপগ্রেডের সময় একটি ড্রাই-রান রি-এক্সপোর্ট আলাদা ব্রাঞ্চে করুন। প্রথমে নতুন রপ্তান করা ভার্সনটি আলাদাভাবে বিল্ড ও রান করুন, যাতে আপনি জানেন কি পরিবর্তন হয়েছে আপনার কাস্টম লেয়ার যুক্ত করার আগে।
তারপর আপনার পরিকল্পিত সিমস (মিডলওয়্যার রেজিস্ট্রেশন, কাস্টম রাউটার গ্রুপ, কাস্টম প্যাকেজ) ব্যবহার করে কাস্টমাইজেশনগুলো পুনরায় প্রয়োগ করুন। জেনারেটেড ফাইলের ভিতর নির্দিষ্ট সার্জিক্যাল এডিট এড়িয়ে চলুন। যদি কোনো পরিবর্তন একটি ইন্টিগ্রেশন পয়েন্টের মাধ্যমে ব্যাক্ত করা না যায়, তবে সেটা একটা সিগন্যাল — একবার নতুন সিম যোগ করুন, তারপর সব ভবিষ্যৎ পরিবর্তন সেখানে পাঠান।
একটি সংক্ষিপ্ত রিগ্রেশন চেকলিস্টে ফোকাস করুন আচরণে:
- অথ ফ্লো কাজ করে (লগইন, টোকেন রিফ্রেশ, লগআউট)
- ৩-৫টি মূল API এন্ডপয়েন্ট একই স্ট্যাটাস কোড এবং শেপ রিটার্ন করে
- প্রতিটি এন্ডপয়েন্টে একটি অনাকাঙ্ক্ষিত পথ (মন্দ ইনপুট, অনুপস্থিত অথ) চেক করুন
- ব্যাকগ্রাউন্ড জব বা সিডিউলড টাস্ক এখনও চলে
- আপনার ডিপ্লয়মেন্ট সেটআপে হেলথ/রেডিনেস এন্ডপয়েন্ট OK রিটার্ন করে
আপনি যদি অডিট লগিং মিডলওয়্যার যোগ করে থাকেন, প্রতিটি রি-এক্সপোর্ট ও মার্জের পরে নিশ্চিত করুন লগে ইউজার আইডি ও রুট নাম একটি রাইট অপারেশনের জন্য আছে।
আপগ্রেডকে কষ্টকর করে তোলা সাধারণ ভুলগুলো
আপনি যদি "এই একবারই" বলে জেনারেটেড ফাইল এডিট করেন, সেটিই আপনার পরবর্তী রি-এক্সপোর্ট নষ্ট করার দ্রুততম উপায়। ছোট বাগ ফিক্স বা হেডার চেক যোগ করার সময় এটা অনাহুত মনে হতে পারে, কিন্তু মাস পরে আপনি আর মনে রাখবেন না কিভাবে বা কেন পরিবর্তন করা হয়েছিল, বা জেনারেটর এখন একই আউটপুট দেয় কি না।
আরও একটি জালতা হল কাস্টম কোড ছড়িয়ে ফেলা: একটি হেল্পার এক প্যাকেজে, কাস্টম অথ চেক অন্যটায়, মিডলওয়্যার টুইক রাউটিংয়ের কাছে, এবং একটি ওয়ান-অফ হ্যান্ডলার ভিন্ন ফোল্ডারে। আর কেউই মালিকানাধীন না হলে প্রতিটি মার্জ একটি খনি-অন্বেষণী কাজ হয়ে যায়। পরিবর্তনগুলো কয়েকটি চিন্তাশীল স্থানে রাখুন।
জেনারেটেড ইন্টারনাল অংশে শক্ত ভাবে বাঁধা রাখা
আপগ্রেড কষ্টকর হয় যখন আপনার কাস্টম কোড জেনারেটেড ইন্টারনাল স্ট্রাক্ট, প্রাইভেট ফিল্ড বা প্যাকেজ লেআউট ডিটেইলে নির্ভর করে। জেনারেটেড কোডে একটি ছোট রিফ্যাক্টর হলেও আপনার বিল্ড ভেঙে যেতে পারে।
নিরাপদ সীমানা:
- কাস্টম এন্ডপয়েন্টগুলোর জন্য আপনি কন্ট্রোল করা request/response DTO ব্যবহার করুন।
- এক্সপোর্টেড ইন্টারফেস বা ফাংশনের মাধ্যমে জেনারেটেড লেয়ারের সাথে ইন্ট্র্যাক্ট করুন, না যে internal টাইপ ব্যবহার করে।
- সম্ভব হলে মিডলওয়্যার ডিসিশনগুলো HTTP primitives (headers, method, path) উপর ভিত্তি করে রাখুন।
প্রয়োজনীয় জায়গায় টেস্ট বাদ দেয়া
মিডলওয়্যার ও রাউটিং বাগগুলো সময় নষ্ট করে কারণ ব্যর্থতা র্যান্ডম 401 বা "endpoint not found" মত দেখায়। কয়েকটি ফোকাসড টেস্ট ঘন্টার কাজ বাঁচায়।
বাস্তব উদাহরণ: আপনি অডিট মিডলওয়্যার যোগ করেন যা লগ করতে রিকোয়েস্ট বডি পড়ে; হঠাৎ কিছু এন্ডপয়েন্ট খালি বডি পেতে শুরু করে। একটি ছোট টেস্ট যা POST পাঠায় রাউটারের মাধ্যমে এবং অডিট সাইড-ইফেক্ট ও হ্যান্ডলার আচরণ দুটোই চেক করে, সেই রিগ্রেশন ধরবে।
রিলিজ-পূর্ব দ্রুত চেকলিস্ট
কাস্টম পরিবর্তন শিপ করার আগে একটি দ্রুত পাস করুন যা পরের রি-এক্সপোর্টে আপনাকে রক্ষা করবে। আপনার কাছে থাকা উচিত ঠিক কী পুনরায় প্রয়োগ করতে হবে, কোথায় এটি আছে এবং কিভাবে তা যাচাই করবেন।
- সব কাস্টম কোড একটি স্পষ্টভাবে নামকৃত প্যাকেজ বা ফোল্ডারে রাখুন (উদাহরণ:
internal/custom/). - জেনারেটেড ওয়্যারিং টাচপয়েন্টগুলো ১-২ ফাইল পর্যন্ত সীমাবদ্ধ রাখুন। এগুলোকে ব্রিজের মতো ট্রিট করুন: একবার রুট রেজিস্টার করুন, একবার মিডলওয়্যার রেজিস্টার করুন।
- মিডলওয়্যার অর্ডার ও কারণটি ডকুমেন্ট করুন ("Auth before rate limiting" এবং কেন)।
- প্রতিটি কাস্টম এন্ডপয়েন্টে অন্তত একটি টেস্ট নিশ্চিত রাখুন।
- একটি পুনরাবৃত্তি যোগ্য আপগ্রেড রুটিন লেখে রাখুন: রি-এক্সপোর্ট, কাস্টম লেয়ার পুনরায় প্রয়োগ, টেস্ট চালান, ডিপ্লয়।
আপনি যদি শুধুমাত্র একটিই কাজ করেন, তবে আপগ্রেড নোট করুন। এটি "ভালো লাগছে" থেকে পরিণত করে "আমরা প্রমাণ করতে পারি এটা এখনও কাজ করে"।
উদাহরণ: অডিট লগিং ও একটি হেলথ এন্ডপয়েন্ট যোগ করা
ধরে নিন আপনি AppMaster থেকে একটি Go ব্যাকএন্ড রপ্তানি করেছেন এবং আপনি দুইটি যোগ করতে চান: রিকোয়েস্ট আইডি সহ অ্যাডমিন অ্যাকশনের জন্য অডিট লগিং, এবং মনিটরিং-এর জন্য একটি সরল /health এন্ডপয়েন্ট। লক্ষ্য হচ্ছে আপনার পরিবর্তনগুলো রি-এক্সপোর্টের পরে সহজে পুনরায় প্রয়োগযোগ্য রাখা।
অডিট লগিংয়ের জন্য কোড রাখুন এমন স্পট-এ যেমন internal/custom/middleware/। মিডলওয়্যারটি করুন (1) X-Request-Id পড়ে বা জেনারেট করে, (2) এটি রিকোয়েস্ট কনটেক্সটে সংরক্ষণ করে, এবং (3) অ্যাডমিন রুটগুলোর জন্য এক লাইনের অডিট লগ করে (মেথড, পাথ, ইউজার আইডি যদি পাওয়া যায়, এবং রেজাল্ট)। প্রতি রিকোয়েস্টে একলাইন লগ রাখুন এবং বড় পে-লোড ডাম্প করা এড়ান।
এটি রাউট নিবন্ধনের কাছে ওয়্যার করুন, যেখানে রুট রেজিস্টার করা হয়। যদি জেনারেটেড রাউটার একটি সিঙ্গেল সেটআপ ফাইল থাকে, সেখানে একটি ছোট হুক যোগ করুন যা আপনার মিডলওয়্যার ইমপোর্ট করে এবং তা শুধুমাত্র অ্যাডমিন গ্রুপে অ্যাপ্লাই করে।
/health এর জন্য একটি ছোট হ্যান্ডলার internal/custom/handlers/health.go এ রাখুন। 200 OK রিটার্ন করুন শর্ট বডি ok সহ। মনিটর যদি প্রয়োজন না করে তবে অথ যোগ করবেন না; যদি করে, তা ডকুমেন্ট করুন।
পরিবর্তনগুলো সহজে পুনরায় প্রয়োগযোগ্য রাখতে কমিটগুলো এইভাবে স্ট্রাকচার করুন:
- কমিট 1:
internal/custom/middleware/audit.goএবং টেস্ট যোগ করা - কমিট 2: অ্যাডমিন রুটে মিডলওয়্যার ওয়্যার করা (সর্বনিম্ন ডিফ)
- কমিট 3:
internal/custom/handlers/health.goযোগ করা এবং/healthরেজিস্টার করা
একটি আপগ্রেড বা রি-এক্সপোর্টের পরে বেসিক ভেরিফাই করুন: অ্যাডমিন রুটগুলো এখনও অথ চায়, রিকোয়েস্ট আইডি অ্যাডমিন লগসে দেখা যায়, /health দ্রুত রেসপন্ড করে, এবং মিডলওয়্যার লাইট লোডে মনোযোগযোগ্য ল্যাটেন্সি যোগ করে না।
পরবর্তী ধাপ: একটি কাস্টমাইজেশন ওয়ার্কফ্লো সেট করুন যা বজায় রাখা যায়
প্রতিটি এক্সপোর্টকে একটি নতুন বিল্ড হিসেবে বিবেচনা করুন যা আপনি পুনরাবৃত্তি করতে পারবেন। আপনার কাস্টম কোডটি এমন লাগবে যেন এটি একটি অ্যাড-অন লেয়ার, পুনর্লিখন নয়।
পরবর্তীবার কোন কাজ নো-কোড মডেলে এবং কোন কাজ কোডে রাখবেন সিদ্ধান্ত নিন। ব্যবসায়িক নিয়ম, ডাটা শেপ, এবং স্ট্যান্ডার্ড CRUD লজিক সাধারণত মডেলে রাখুন। এক-অফ ইন্টেগ্রেশন এবং কোম্পানী-নির্দিষ্ট মিডলওয়্যার সাধারণত কাস্টম কোডে রাখুন।
আপনি যদি AppMaster (appmaster.io) ব্যবহার করেন, জেনারেটেড Go ব্যাকএন্ডের চারপাশে একটি পরিষ্কার এক্সটেনশন লেয়ার ডিজাইন করুন: মিডলওয়্যার, রুট, এবং হেল্পারগুলো একটি ছোট সেট ফোল্ডারে রাখুন যাতে আপনি রি-এক্সপোর্ট জুড়ে এগুলো বহন করতে পারেন, এবং জেনারেটর-মালিকানাধীন ফাইলগুলি অপরিবর্তিত রাখুন।
একটি ব্যবহারিক চূড়ান্ত চেক: যদি একজন টিমমেট এক্সপোর্ট করতে পারে, আপনার ধাপগুলো প্রয়োগ করতে পারে এবং এক ঘন্টার মধ্যে একই ফল পেতে পারে, আপনার ওয়ার্কফ্লো রক্ষণীয় যোগ্য।
প্রশ্নোত্তর
Don’t edit generator-owned files. Put your changes in a clearly owned package (for example, internal/custom/) and connect them through one small integration point near server startup. That way a re-export mostly replaces generated code while your custom layer stays intact.
Assume anything marked with comments like “Code generated” or “DO NOT EDIT” will be rewritten. Also watch for very uniform folder structures, repetitive naming, and minimal human comments; those are typical generator fingerprints. Your safest rule is to treat all of that as read-only even if it compiles after you edit it.
Keep one “hook” file that imports your custom package and registers everything: middleware, extra routes, and any small wiring. If you find yourself touching five routing files or multiple generated handlers, you’re drifting toward a fork that will be painful to upgrade.
Write middleware in your own package and keep it narrow, like request IDs, audit logging, rate limits, or special headers. Then register it once at the router or HTTP stack creation point, not per-route inside generated handlers. A quick httptest check for one expected header or status code is usually enough to catch regressions after re-export.
Define the endpoint contract first, then implement the handler in your custom package and register the route at the same integration point you use for middleware. Keep the handler simple: validate input, call existing services, return a consistent error shape, and avoid copying generated handler logic. This keeps your change portable to a fresh export.
Routes can shift when the generator changes route registration order, grouping, or middleware chains. To protect yourself, rely on a stable registration seam and keep middleware order documented right next to the registration line. If ordering matters (for example, auth before audit), encode it intentionally and verify behavior with a small test.
If you implement the same rule in both places, they will drift over time and you’ll get confusing behavior. Put business rules that non-developers should adjust (fields, validation, workflows, permissions) in the no-code model, and keep infrastructure concerns (logging, auth integration, rate limits, headers) in your custom Go layer. The split should be obvious to anyone reading the repo.
Generated DTOs and internal structs can change across exports, so isolate that churn at the boundary. Convert inputs into your own internal structs, run your domain logic on those, then convert outputs back at the edge. When types shift after re-export, you update one adapter instead of chasing compile errors across your whole custom layer.
Separate generated updates from your custom work in Git so you can see what changed and why. A practical flow is to commit the re-exported generated changes first, then commit the minimal wiring and custom-layer adjustments. Keeping a short custom changelog that says what you added and where it lives makes the next upgrade much faster.
Do a dry-run re-export in a separate branch, build it, and run a short regression pass before merging your custom layer back in. After that, reapply customizations through the same seams each time, then validate a few key endpoints plus one unhappy path per endpoint. If something can’t be expressed through a seam, add one new seam once and keep future changes flowing through it.


