নতুন কোনো গো প্রোজেক্টে pkg/ ডিরেক্টরি দেখলেই আমি অনেকটা নিশ্চিত হয়ে যাই যে এটা এক সময় জাঙ্ক ড্রয়ারে পরিণত হবে। মানুষ সাধারণত pkg/-কে পাবলি ফোল্ডার হিসেবে ব্যবহার করে যাতে পরে কিছু শেয়ার করা যায়, কিন্তু বাস্তবে তা কখনও ঘটে না। বরং সেখানে আজেবাজে হেল্পার ফাংশন জমে পুরো প্রোজেক্টে এক বিশৃঙ্খলা তৈরি করে। আমি আমার প্রোজেক্টগুলোতে প্রায় সবকিছুই internal/ ফোল্ডারের ভেতর রাখি যাতে ভুলবশত কোনো অপ্রয়োজনীয় কাপলিং তৈরি না হয়। একটি সঠিক Go Project Structure আপনার সার্ভিসকে দীর্ঘমেয়াদী রক্ষণাবেক্ষণে অনেক সাহায্য করে।

ম্যানুয়ালি ওয়্যারিং: ফ্রেমওয়ার্ক কি আসলেই দরকার?

আমি অনেকদিন ধরে উইবার (Uber) এর fx বা গুগলের wire এর মতো ডিপেন্ডেন্সি ইনজেকশন ফ্রেমওয়ার্কগুলো ব্যবহার করা বন্ধ করে দিয়েছি। অনেকে হয়তো বলবে, "এগুলো তো জাস্ট বয়লারপ্লেট কমায়"। কিন্তু আমার কাছে ৩০ লাইনের ম্যানুয়াল স্ট্রাক্ট ইনিশিয়ালাইজেশন অনেক বেশি স্বস্তিদায়ক। কোন প্রোভাইডার কেন রেজিস্টার হয়নি বা রিফ্লেকশন-বেসড কনটেইনার কেন ক্রিপ্টিক এরর দিচ্ছে—এসব নিয়ে ২০ মিনিট ডিবাগ করার চেয়ে সরাসরি কোড দেখাই ভালো।

main.go ফাইলটা দেখলেই আপনি আপনার প্রোজেক্টের পুরো ডিপেন্ডেন্সি গ্রাফ পরিষ্কার দেখতে পাবেন। কোনো ম্যাজিক নেই, আর কিছু যদি মিস হয় তবে কম্পাইলারই আপনাকে বলে দেবে।

আমি যে লেআউট ব্যবহার করি

এটি কোনো বৈপ্লবিক লেআউট নয়, তবে যথেষ্ট ফ্ল্যাট যাতে ফোল্ডার গোলকধাঁধায় হারিয়ে না যেতে হয়।

.
├── cmd/service/main.go  # ওয়্যারিংয়ের মূল জায়গা
├── internal/
│   ├── api/             # ট্রান্সপোর্ট লেয়ার (HTTP/gRPC)
│   ├── domain/          # ইন্টারফেস এবং কন্ট্রাক্ট
│   ├── logic/           # বিজনেজ লজিক বা ব্রেইন
│   ├── store/           # পারসিস্টেন্স বা ডাটাবেস
│   └── config/          # এনভায়রনমেন্ট কনফিগারেশন
└── Makefile             # রিয়েল লাইফ ইউআই

হ্যান্ড-ক্রাফটেড এসকিউএল (SQL) এর আনন্দ ও যন্ত্রণা

আমি ওআরএম (ORM) বা এসকিউএল জেনারেটর যতটা সম্ভব এড়িয়ে চলি। আমি sqlc ট্রাই করেছিলাম, কিন্তু কমপ্লেক্স জয়েন বা পোস্টগ্রেসের স্পেসিফিক ফিচার নিয়ে ডিল করতে গিয়ে বারবার পার্সারের সাথে ফাইট করতে হয়েছে।

আমার মনে হয় র-এসকিউএল (Raw SQL) লেখা আর স্ট্রাক্টে ম্যাপ করা অনেক বেশি ফ্লেক্সিবল। মাঝেমধ্যে গো-এর এই 'ভার্বোসিটি ট্যাক্স' (Verbosity Tax) নিয়ে বিরক্ত লাগে, বিশেষ করে যখন প্রতিটি ফিল্ড ম্যানুয়ালি স্ক্যান করতে হয়। তবে pgx/v5 আসার পর কাজটা কিছুটা সহজ হয়েছে। জেনেরিক্স ব্যবহার করে ম্যানুয়াল স্ক্যানিংয়ের অংশটা এখন অনেক কম।

// pgx/v5 জেনেরিক্স ব্যবহার করে
p, err := pgx.CollectOneRow(rows, pgx.RowToAddrOfStructByName[Account])
if err != nil {
	return nil, err
}

ডোমেইন লেয়ার: বাফার হিসেবে ব্যবহার

আমি internal/domain ফোল্ডারটাকে একটা বাফার হিসেবে দেখি যেখানে শুধু ইন্টারফেস আর স্ট্রাক্ট থাকে। কোনো ডাটাবেস ট্যাগ বা জেসন ট্যাগ এখানে থাকা উচিত নয়। বিজনেজ লজিক ইমপ্লিমেন্ট করার সময় আমি কখনও সরাসরি এপিআই (API) বা স্টোর ইমপোর্ট করি না। টেস্টিংয়ের সময় রিয়েল ডাটাবেস ছাড়া মক (Mock) ডেটা দিয়ে টেস্ট করার এটাই সবচেয়ে সহজ উপায়।

আমার বিশ্বাস, যদি কোনো প্রোজেক্ট খোলার ৬০ সেকেন্ডের মধ্যে আপনি নির্দিষ্ট বিজনেস রুল বা কোয়েরি খুঁজে না পান, তবে আপনার Go Project Structure এ বড় কোনো গলদ আছে। আমি সবকিছু খোঁজার জন্য 'fzf' ব্যবহার করলেও লেআউট এমনভাবে বানাই যাতে এলএসপি (LSP) আমাকে সঠিক জায়গায় ল্যান্ড করাতে পারে।

সহজ এবং ফ্ল্যাট স্ট্রাকচার সাধারণত দীর্ঘমেয়াদে জয়ী হয়। শুরুতে অনেক বেশি ফোল্ডার বা সফিস্টিকেটেড লেআউট নিলে পরবর্তীতে কগনিটিভ লোড অনেক বেড়ে যায়।

গো (Go) ল্যাঙ্গুয়েজ ব্যবহার করে মাইক্রোসার্ভিস তৈরির জন্য সেরা Go Project Structure কোনটি এবং কেন ম্যানুয়ালি ডিপেন্ডেন্সি ম্যানেজমেন্ট ও হ্যান্ড-ক্রাফটেড SQL কার্যকর, তা কোডসহ জানুন।

Asaduzzaman Pavel

About the Author

Asaduzzaman Pavel is a Software Engineer who actually enjoys the friction of a well-architected system. He has over 15 years of experience building high-performance backends and infrastructure that can actually handle the real-world chaos of scale.

Currently looking for new opportunities to build something amazing.