তোমার Project-এ Coupled Code কীভাবে খুঁজে বের করবে?
A highly motivated and experienced full-stack developer with a proven track record of developing and deploying web applications. Skilled in a range of programming languages and frameworks, as well as database technologies. Comfortable working in a fast-paced environment and able to adapt to new technologies quickly. A team player who is also able to work independently when required.
Coupled code খোঁজা মানে হচ্ছে তোমার codebase-এ এমন জায়গা খুঁজে বের করা যেখানে একটা অংশ আরেকটার উপর বেশি depend করছে। এটা একটা detective work — তুমি clue খুঁজবে, pattern দেখবে, এবং সমস্যা চিহ্নিত করবে।
চলো step by step শিখি কীভাবে এটা করতে হয়।
কেন Coupled Code খোঁজা দরকার?
প্রথমে বুঝি কেন এটা important:
Coupled code-এর সমস্যা:
একটা জায়গায় change করলে অন্য ১০ টা জায়গায় bug হয়
Testing করা কঠিন হয়ে যায়
নতুন feature যোগ করতে গেলে পুরো system নাড়াচাড়া করতে হয়
Code maintain করা nightmare হয়ে যায়
তাই early detection করা better — যত আগে ধরবে, তত সহজে fix করতে পারবে।
Signal #1: "new" Keyword সরাসরি ইউজ হচ্ছে
কী খুঁজবে?
Function বা method-এর ভিতরে যদি সরাসরি concrete type create করা হয়, সেটা coupling-এর sign।
Example: Coupled Code
func ProcessOrder(orderID string) {
// এখানে সমস্যা: সরাসরি MySQL create করছে
db := &MySQL{
host: "localhost",
port: 3306,
}
order := db.GetOrder(orderID)
fmt.Println(order)
}
কেন এটা সমস্যা?
ProcessOrder()শুধু MySQL-এর সাথেই কাজ করবেPostgreSQL বা MongoDB দিতে চাইলে পুরো function rewrite করতে হবে
Test-এ fake database দেওয়া impossible
কীভাবে খুঁজবে?
তোমার code editor-এ search করো:
new(&TypeName{Constructor calls (
NewMySQL(),CreateConnection())
Red flag: যদি এগুলো function/method-এর ভিতরে থাকে (global level বা main function ছাড়া)।
Signal #2: Import Statement-এ Concrete Package
কী খুঁজবে?
High-level package যদি low-level concrete package import করে, সেটা tight coupling।
Example: Coupled Structure
package service
import (
"myapp/database/mysql" // ⚠️ Concrete implementation import
"myapp/cache/redis" // ⚠️ Concrete implementation import
)
type UserService struct {
db *mysql.MySQL // ⚠️ Concrete type dependency
cache *redis.Redis // ⚠️ Concrete type dependency
}
কেন এটা সমস্যা?
UserServiceজানে MySQL এবং Redis-এর internal detailsDatabase বদলাতে গেলে
UserServicechange করতে হবেএই package অন্য project-এ reuse করা impossible
কীভাবে খুঁজবে?
১. তোমার business logic file গুলো open করো ২. Import section দেখো ৩. Question করো: "এই package কি implementation details জানা উচিত?"
Red flag patterns:
import "myapp/database/mysql"
import "myapp/storage/s3"
import "myapp/payment/stripe"
import "myapp/email/sendgrid"
এগুলো সব concrete implementation। Business logic-এ এদের direct import থাকা উচিত না।
Signal #3: Type Assertion বারবার ব্যবহার
কী খুঁজবে?
যদি তুমি বারবার .(Type) type assertion করছো, মানে তোমার abstraction ঠিকমতো কাজ করছে না।
Example: Coupled Code
func ProcessStorage(s interface{}) {
// ⚠️ Concrete type check করতে হচ্ছে
if db, ok := s.(*MySQL); ok {
db.Connect()
db.Query("SELECT * FROM users")
} else if file, ok := s.(*FileStorage); ok {
file.Open()
file.Read()
}
// আরো type check...
}
কেন এটা সমস্যা?
নতুন storage type যোগ করতে গেলে এই function modify করতে হবে
Open/Closed Principle violate করছে
Interface제대로 design করা হয়নি
ভালো Alternative
type Storage interface {
Initialize() error
Fetch(query string) ([]byte, error)
}
func ProcessStorage(s Storage) {
s.Initialize()
data, _ := s.Fetch("users")
fmt.Println(data)
}
কীভাবে খুঁজবে?
Search করো:
.(— type assertionswitch v := x.(type)— type switch
Red flag: যদি same function-এ multiple concrete types check করা হয়।
Signal #4: Testing-এ অসুবিধা
কী খুঁজবে?
যদি unit test লিখতে গিয়ে এসব সমস্যা হয়, তাহলে coupling আছে:
Example: Test করতে পারছো না
// এই function test করতে চাও
func CreateUser(name string) error {
db := &MySQL{host: "production.db.com"} // ⚠️ Production DB!
return db.Insert("users", name)
}
// Test লিখতে গেলে...
func TestCreateUser(t *testing.T) {
// সমস্যা: Real production database-এ connect হবে!
// Fake database inject করার কোনো উপায় নেই
err := CreateUser("Ahmed")
// এই test run করা dangerous
}
Signs of Coupling in Tests:
১. External dependency দরকার পড়ে:
Real database setup করতে হয়
Real API call করতে হয়
File system access লাগে
২. Test slow হয়ে যায়:
Network calls
Database queries
File I/O operations
৩. Test brittle হয়:
একটা service down থাকলে test fail করে
Environment-এর উপর depend করে
কীভাবে খুঁজবে?
১. Existing tests দেখো:
Setup code লম্বা হয়ে যাচ্ছে?
External services mock করা হচ্ছে?
Tests কি slow?
২. যেখানে test নেই, সেখানে লিখতে চেষ্টা করো:
Dependency inject করতে পারছো?
Mock বানাতে পারছো?
Isolated test possible?
Red flag: যদি test লিখতে গিয়ে whole system setup করতে হয়।
Signal #5: একই Code বারবার Copy-Paste
কী খুঁজবে?
Similar code different জায়গায় repeat হচ্ছে — তবে slightly different concrete types দিয়ে।
Example: Duplication due to Coupling
// MySQL-এর জন্য
func SaveUserToMySQL(user User) {
db := &MySQL{}
db.Connect()
db.Execute("INSERT INTO users...")
}
// PostgreSQL-এর জন্য
func SaveUserToPostgres(user User) {
db := &Postgres{}
db.Connect()
db.Execute("INSERT INTO users...")
}
// MongoDB-এর জন্য
func SaveUserToMongo(user User) {
db := &MongoDB{}
db.Connect()
db.Execute("INSERT INTO users...")
}
কেন এটা সমস্যা?
একই logic তিনবার লেখা হচ্ছে
Bug fix করতে গেলে তিন জায়গায় fix করতে হবে
নতুন database যোগ করতে গেলে আরেকটা function লিখতে হবে
ভালো Alternative
type Database interface {
Connect() error
Execute(query string) error
}
func SaveUser(user User, db Database) {
db.Connect()
db.Execute("INSERT INTO users...")
}
কীভাবে খুঁজবে?
১. Similar function names খুঁজো:
ProcessWithMySQL()এবংProcessWithPostgres()SendEmailViaSMTP()এবংSendEmailViaAPI()
২. Code diff tools ইউজ করো:
দুটো file পাশাপাশি রাখো
দেখো structure same কিনা, শুধু type names আলাদা
Red flag: একই pattern বারবার, শুধু concrete types different।
Signal #6: অনেক Parameters Function-এ
কী খুঁজবে?
Function যদি অনেকগুলো concrete dependencies parameter হিসেবে নেয়।
Example: Parameter Hell
func ProcessOrder(
mysqlDB *MySQL,
redisCache *Redis,
stripePayment *Stripe,
sendgridEmail *Sendgrid,
s3Storage *S3,
orderID string,
) error {
// অনেকগুলো concrete dependencies
}
কেন এটা সমস্যা?
Function signature বদলালে everywhere update করতে হবে
Testing-এ সব dependencies mock করতে হবে
নতুন dependency যোগ করা painful
ভালো Alternative
type OrderDependencies struct {
DB Database
Cache Cache
Payment PaymentGateway
Email EmailService
Storage Storage
}
func ProcessOrder(deps OrderDependencies, orderID string) error {
// Clean and extensible
}
কীভাবে খুঁজবে?
১. Function signatures দেখো ২. Count করো: 3+ pointer parameters আছে? ৩. Check করো: সব parameters কি concrete types?
Red flag: 4+ concrete type parameters।
Signal #7: "God Object" বা বড় Struct
কী খুঁজবে?
একটা struct যেটা অনেক কিছু জানে এবং অনেক কিছু করে।
Example: God Object
type Application struct {
mysqlDB *MySQL
postgresDB *Postgres
redisCache *Redis
s3Storage *S3
stripePayment *Stripe
twilioSMS *Twilio
sendgridEmail *Sendgrid
// আরো 20+ fields...
}
func (app *Application) DoEverything() {
// 500 lines of code
}
কেন এটা সমস্যা?
এক জায়গায় too many responsibilities
Change করতে গেলে impact analysis কঠিন
Reuse করা impossible
Testing nightmare
কীভাবে খুঁজবে?
১. Struct definitions খুঁজো যেখানে 10+ fields ২. Methods খুঁজো যেখানে 100+ lines ৩. Check করো: একটা struct কি multiple concerns handle করছে?
Red flags:
UserAuthPaymentEmailHandler (multiple responsibilities in name)
500+ line methods
Struct-এ 15+ dependencies
Signal #8: Circular Dependencies
কী খুঁজবে?
Package A imports Package B, এবং Package B imports Package A — এটা circular dependency।
Example: Circular Import
package user
import "myapp/order"
type User struct {
Orders []order.Order // user depends on order
}
package order
import "myapp/user"
type Order struct {
User user.User // order depends on user
}
কেন এটা সমস্যা?
Go-তে compile-ই হবে না!
Design fundamentally flawed
Strong coupling-এর ultimate sign
কীভাবে খুঁজবে?
Go automatically detect করবে:
package myapp/user
imports myapp/order
imports myapp/user: import cycle not allowed
Solution approach:
Common interface আলাদা package-এ রাখো
Dependency direction ঠিক করো (high-level → low-level)
Domain boundaries properly define করো
Practical Exercise: তোমার Project Analyze করো
Step 1: Quick Scan (10 minutes)
Terminal-এ এই commands run করো:
# 1. Check করো কোন files সবচেয়ে বড়
find . -name "*.go" -exec wc -l {} \; | sort -rn | head -10
# 2. "new" keyword কতবার ইউজ হয়েছে
grep -r "new(" . --include="*.go" | wc -l
# 3. Type assertions খুঁজো
grep -r "\.\(" . --include="*.go" | head -20
# 4. Import statements analyze করো
grep -r "^import" . --include="*.go" | grep "database\|mysql\|postgres"
Step 2: Manual Review (30 minutes)
১. সবচেয়ে বড় file open করো:
Structure দেখো
Dependencies count করো
একটা function কতগুলো concrete types ইউজ করছে?
২. Main business logic file খুঁজো:
service/,handler/,controller/folders দেখোImport statements analyze করো
Concrete types সরাসরি ইউজ হচ্ছে?
৩. Test files দেখো:
Test setup কতটা complicated?
Mock করা হচ্ছে কিনা?
Test coverage কম কেন?
Step 3: Create a Coupling Report
একটা document বানাও:
# Coupling Analysis Report
## High Priority Issues
1. UserService directly creates MySQL connection
- File: service/user.go:45
- Impact: Cannot test without real DB
- Solution: Inject Database interface
2. PaymentHandler imports stripe package
- File: handler/payment.go:12
- Impact: Tied to one payment provider
- Solution: Create PaymentGateway interface
## Medium Priority
...
## Low Priority
...
Coupling Score Calculator
তোমার codebase-এর coupling level measure করার একটা সহজ formula:
Coupling Score =
(Direct Type Creation × 3) +
(Concrete Package Imports × 2) +
(Type Assertions × 2) +
(Large Structs with 10+ fields × 1) +
(Functions with 5+ params × 1)
Scoring:
0-20: ভালো! Low coupling
21-50: Okay, improvement সম্ভব
51-100: Medium coupling, refactor করা উচিত
100+: High coupling, serious refactoring দরকার
Automated Tools ইউজ করো
1. Go Vet
Built-in tool, basic issues ধরে:
go vet ./...
2. Golint
Code style এবং best practices check করে:
go install golang.org/x/lint/golint@latest
golint ./...
3. Go-Critic
Advanced linter, coupling patterns detect করে:
go install github.com/go-critic/go-critic/cmd/gocritic@latest
gocritic check ./...
4. Staticcheck
Comprehensive static analysis:
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...
Visual Dependency Analysis
Package Dependency Graph বানাও
# godepgraph install করো
go install github.com/kisielk/godepgraph@latest
# Dependency graph generate করো
godepgraph -s -o myapp | dot -Tpng -o dependencies.png
এই graph দেখলে বুঝবে:
কোন packages সবচেয়ে বেশি imported
Circular dependencies আছে কিনা
Dependency direction ঠিক আছে কিনা
একটা Real Example: Refactoring Journey
Before: Highly Coupled
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
type UserHandler struct{}
func (h UserHandler) CreateUser(name, email string) error {
// ⚠️ Direct MySQL connection
db, err := sql.Open("mysql", "user:pass@tcp(localhost:3306)/db")
if err != nil {
return err
}
defer db.Close()
// ⚠️ Direct SQL query
_, err = db.Exec("INSERT INTO users (name, email) VALUES (?, ?)", name, email)
return err
}
Problems identified:
Handler directly creates database connection
Testing impossible without real MySQL
Cannot switch databases
SQL logic mixed with handler logic
After: Decoupled
package main
// Interface defines behavior
type UserRepository interface {
Create(name, email string) error
}
// Handler depends on interface
type UserHandler struct {
repo UserRepository
}
func NewUserHandler(repo UserRepository) *UserHandler {
return &UserHandler{repo: repo}
}
func (h *UserHandler) CreateUser(name, email string) error {
return h.repo.Create(name, email)
}
// Concrete implementation in separate package
type MySQLUserRepository struct {
db *sql.DB
}
func (r *MySQLUserRepository) Create(name, email string) error {
_, err := r.db.Exec("INSERT INTO users (name, email) VALUES (?, ?)", name, email)
return err
}
// Test-এর জন্য mock
type MockUserRepository struct {
CreateFunc func(name, email string) error
}
func (m *MockUserRepository) Create(name, email string) error {
return m.CreateFunc(name, email)
}
Benefits: ✅ Handler testable with mock repository
✅ Can switch from MySQL to Postgres easily
✅ Clear separation of concerns
✅ Follows dependency inversion principle
Action Plan: কী করবে এখন?
Week 1: Discovery
[ ] তোমার codebase scan করো
[ ] Top 5 coupled areas identify করো
[ ] Coupling report লিখো
Week 2: Small Wins
[ ] সবচেয়ে ছোট coupled function refactor করো
[ ] Interface extract করো
[ ] Test লিখো
Week 3: Medium Refactoring
[ ] একটা service layer decouple করো
[ ] Repository pattern implement করো
[ ] Integration tests add করো
Week 4: Review & Document
[ ] Coupling score আবার measure করো
[ ] Improvement document করো
[ ] Team-এর সাথে share করো
শেষ কথা
Coupled code খোঁজা একটা skill যেটা practice-এর সাথে develop হয়। শুরুতে কঠিন মনে হতে পারে, কিন্তু এই signals মাথায় রাখলে ধীরে ধীরে pattern চিনতে শুরু করবে।
মনে রাখো:
Perfect code খোঁজো না — improvement খোঁজো
একবারে সব fix করতে যেও না — incremental refactoring করো
Tests লিখো — refactoring-এর আগে এবং পরে
Document করো — কেন change করলে সেটা লিখো
Coupling detect করা হলো প্রথম step। Decoupling করা হবে পরের journey।
Happy refactoring!



