zRY (Don’t Repeat Yourself) প্যাটার্ন কি?
DRY (Don’t Repeat Yourself) একটি সফটওয়্যার ডেভেলপমেন্ট প্যাটার্ন যা কোড রিইউসেবিলিটি এবং স্কেলেবিলিটি বাড়াতে সাহায্য করে। এর মূল ধারণা হল: কোডের পুনরাবৃত্তি এড়ানো, অর্থাৎ একই কোড বারবার না লিখে এক জায়গায় সঠিকভাবে কোড লেখা এবং রিইউজ করা।
DRY প্যাটার্নের উদ্দেশ্য হল:
- কোড পুনঃব্যবহারযোগ্য এবং রক্ষণাবেক্ষণযোগ্য করা।
- কোডে গড়বড় এবং বাগ কমিয়ে আনা।
- কোড পড়তে এবং বুঝতে সহজ করা।
TypeORM-এ DRY প্যাটার্ন অনুসরণ করলে, আপনি ডেটাবেস সম্পর্কিত কাজগুলোকে আরও পরিষ্কার, সহজ এবং মডুলার করতে পারেন।
TypeORM এ DRY প্যাটার্ন মেনে কোড লেখা
TypeORM ব্যবহার করার সময় DRY প্যাটার্ন মেনে কোড লেখা অনেক সুবিধা দেয়। এর মাধ্যমে আপনি ডেটাবেস অপারেশনগুলিকে পুনঃব্যবহারযোগ্য এবং অ্যাবস্ট্রাক্ট (abstract) করে রাখতে পারেন, যাতে কোডের গঠন পরিষ্কার এবং কার্যকরী হয়। এখানে আমরা দেখব TypeORM এ DRY প্যাটার্ন কীভাবে প্রয়োগ করতে পারি।
১. Repository Pattern ব্যবহার করা
Repository Pattern হল একটি ডিজাইন প্যাটার্ন, যা TypeORM এ ডেটাবেস অপারেশনগুলিকে এক জায়গায় রাখে। এটি ডেটাবেস টেবিলের জন্য CRUD অপারেশনগুলির সাধারণ কোড পুনরাবৃত্তি এড়াতে সাহায্য করে।
উদাহরণ:
ধরা যাক, আমাদের দুটি Entity আছে: User এবং Post। প্রতিটি Entity এর জন্য Repository Pattern ব্যবহার করা উচিত, যাতে একই ধরনের ডেটাবেস অপারেশন কোডে পুনরাবৃত্তি না হয়।
import { EntityRepository, Repository } from "typeorm";
import { User } from "../entity/User";
@EntityRepository(User)
export class UserRepository extends Repository<User> {
// Retrieve users by name
async findByName(name: string) {
return this.find({ where: { name } });
}
// Create and save a new user
async createAndSaveUser(name: string, email: string) {
const user = new User();
user.name = name;
user.email = email;
return this.save(user);
}
}
এখানে, UserRepository ক্লাসে সাধারণ ডেটাবেস অপারেশনগুলি (যেমন findByName এবং createAndSaveUser) রাখা হয়েছে। এর ফলে কোড পুনঃব্যবহারযোগ্য হয় এবং যেখানে দরকার সেখানে এটি সহজে ব্যবহার করা যায়।
২. Services ব্যবহার করা
Service Layer ব্যবহার করার মাধ্যমে ডেটাবেসের সাথে যোগাযোগের লজিক আলাদা করা হয়। এতে অ্যাপ্লিকেশনের মূল লজিক এবং ডেটাবেস অপারেশন আলাদা থাকে, এবং এই ধরনের কোড পুনরাবৃত্তি কমে যায়।
উদাহরণ:
import { getCustomRepository } from "typeorm";
import { UserRepository } from "../repositories/UserRepository";
import { User } from "../entity/User";
class UserService {
// Get users by name
async getUsersByName(name: string): Promise<User[]> {
const userRepository = getCustomRepository(UserRepository);
return userRepository.findByName(name);
}
// Create a new user
async createUser(name: string, email: string): Promise<User> {
const userRepository = getCustomRepository(UserRepository);
return userRepository.createAndSaveUser(name, email);
}
}
এখানে, UserService ক্লাসে ডেটাবেসের সাথে সম্পর্কিত লজিক রাখলে, ডেটাবেস অপারেশনগুলো এক জায়গায় থাকে এবং UserRepository ক্লাসটি কোড পুনরাবৃত্তি না করে ব্যবহার করা যেতে পারে।
৩. Common Functions ব্যবহার করা
Utility Functions বা Helper Functions ব্যবহার করে সাধারণ কাজগুলো এক জায়গায় রাখুন। উদাহরণস্বরূপ, আপনি যদি বারবার একই ধরনের ডেটা ভ্যালিডেশন বা ক্যালকুলেশন করেন, তাহলে সেই কাজগুলো একটি ফাংশনে রেখে ব্যবহার করুন।
উদাহরণ:
// utils/validation.ts
export const validateEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
// services/UserService.ts
import { validateEmail } from "../utils/validation";
class UserService {
async createUser(name: string, email: string): Promise<User> {
if (!validateEmail(email)) {
throw new Error("Invalid email format");
}
const userRepository = getCustomRepository(UserRepository);
return userRepository.createAndSaveUser(name, email);
}
}
এখানে, validateEmail একটি সাধারণ ভ্যালিডেশন ফাংশন তৈরি করা হয়েছে, যা পুনঃব্যবহারযোগ্য এবং কোডের পুনরাবৃত্তি এড়ায়।
৪. Abstract Class এবং Inheritance ব্যবহার করা
কখনও কখনও আপনার প্রোজেক্টে বিভিন্ন ধরনের ডেটাবেস টেবিলের জন্য একই ধরনের অপারেশন দরকার হয়। আপনি একাধিক রিপোজিটরি তৈরি করার পরিবর্তে একটি Abstract Class ব্যবহার করে সাধারণ অপারেশনগুলো একটি জায়গায় রাখতে পারেন এবং অন্যান্য ক্লাসে ইনহেরিট করতে পারেন।
উদাহরণ:
import { EntityRepository, Repository } from "typeorm";
// Abstract Repository
export abstract class AbstractRepository<T> extends Repository<T> {
async findById(id: number) {
return this.findOne(id);
}
async findAll() {
return this.find();
}
async saveEntity(entity: T) {
return this.save(entity);
}
}
// Specific Repository
@EntityRepository(User)
export class UserRepository extends AbstractRepository<User> {
// Specific methods related to User can go here
}
এখানে, AbstractRepository ক্লাসে সাধারণ অপারেশনগুলো রাখা হয়েছে এবং UserRepository ক্লাসে সেই সাধারণ ফাংশনগুলো ইনহেরিট করা হয়েছে। এতে কোড পুনঃব্যবহারযোগ্য হয় এবং আপনার কোডে পুনরাবৃত্তি কমে যায়।
৫. Migration এবং Seeders ব্যবহারের মাধ্যমে ডেটাবেস মডেল আপডেট করা
TypeORM Migrations এবং Seeders এর মাধ্যমে ডেটাবেসের কাঠামো এবং ডেটা আপডেট করতে পারেন। এতে কোড পুনরাবৃত্তি কমে এবং ডেটাবেস স্কিমা নির্দিষ্টভাবে সংরক্ষিত থাকে।
Migration উদাহরণ:
typeorm migration:create -n UserMigration
এর পর, নতুন মাইগ্রেশন ফাইল তৈরি হলে সেখানে আপনি ডেটাবেসের আপডেট বা পরিবর্তন করতে পারবেন। উদাহরণস্বরূপ, নতুন টেবিল তৈরি বা কলাম যোগ করার জন্য:
import {MigrationInterface, QueryRunner} from "typeorm";
export class UserMigration implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255), email VARCHAR(255))`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP TABLE users`);
}
}
এখানে, Migrations ব্যবহার করার মাধ্যমে আপনি কোড পুনঃব্যবহারযোগ্য এবং স্কেলেবল করতে পারেন, যেখানে ডেটাবেসের পরিবর্তনগুলো একটি নির্দিষ্ট স্কিমায় রাখা যায়।
সারাংশ
DRY (Don’t Repeat Yourself) প্যাটার্ন TypeORM এ কোডের পুনঃব্যবহারযোগ্যতা এবং কার্যকারিতা বাড়াতে সাহায্য করে। Repository Pattern, Services, Helper Functions, Abstract Classes, এবং Migrations ব্যবহার করে আপনি পুনরাবৃত্তি এড়িয়ে যাবেন এবং কোডটিকে আরও পরিষ্কার, রক্ষণাবেক্ষণযোগ্য এবং স্কেলেবল রাখতে পারবেন। TypeORM এর মাধ্যমে এসব প্যাটার্ন ব্যবহার করে আপনি আরও প্রফেশনাল, পড়তে সুবিধাজনক এবং সহজে রক্ষণাবেক্ষণযোগ্য কোড তৈরি করতে পারবেন।
Read more