به حداکثر رساندن استفاده مجدد از کد در برنامه های جاوا به معنای نوشتن کدی است که خواندن، درک و نگهداری آسان باشد. در اینجا هشت راه برای شروع ارائه شده است.
نوشتن کد قابل استفاده مجدد برای هر توسعه دهنده نرم افزار یک مهارت حیاتی است و هر مهندس باید بداند که چگونه استفاده مجدد از کد را به حداکثر برساند. امروزه، توسعه دهندگان اغلب این بهانه را به کار می برند که نیازی به زحمت نوشتن کدهای با کیفیت بالا نیست، زیرا سرویس های میکرو ذاتا کوچک و کارآمد هستند. با این حال، حتی میکروسرویس ها نیز می توانند بسیار بزرگ شوند و زمان لازم برای خواندن و درک کد به زودی ۱۰ برابر بیشتر از زمانی است که برای اولین بار نوشته شده است.
حل اشکالات یا افزودن ویژگیهای جدید زمانی که کد شما از ابتدا به خوبی نوشته نشده باشد، کار بسیار بیشتری میطلبد. در موارد شدید، تیمها را دیدهام که کل برنامه را دور انداخته و با کد جدید شروع به کار میکنند. زمانی که این اتفاق می افتد نه تنها زمان تلف می شود، بلکه توسعه دهندگان نیز سرزنش می شوند و ممکن است شغل خود را از دست بدهند.
این مقاله هشت دستورالعمل آزمایش شده را برای نوشتن کدهای قابل استفاده مجدد در جاوا معرفی می کند.
۸ دستورالعمل برای نوشتن کد جاوا قابل استفاده مجدد
- قوانین کد خود را تعریف کنید
- API های خود را مستند کنید
- از قراردادهای نامگذاری کد استاندارد پیروی کنید
- کلاس ها و روش های منسجمی بنویسید
- کلاس های خود را جدا کنید
- آن را جامد نگه دارید
- در صورت لزوم از الگوهای طراحی استفاده کنید
- چرخ را دوباره اختراع نکنید
قوانین کد خود را تعریف کنید
اولین قدم برای نوشتن کد قابل استفاده مجدد این است که استانداردهای کد را با تیم خود تعریف کنید. در غیر این صورت، کد خیلی سریع خراب می شود. در صورت عدم همسویی با تیم، بحثهای بیمعنی در مورد پیادهسازی کد نیز اغلب اتفاق میافتد. همچنین میخواهید یک طراحی کد پایه برای مشکلاتی که میخواهید نرمافزار حل کند، تعیین کنید.
هنگامی که استانداردها و طراحی کد را دریافت کردید، وقت آن است که دستورالعملهایی را برای کد خود تعریف کنید. دستورالعمل های کد قوانین کد شما را تعیین می کند:
- نام رمز
- تعداد خط کلاس و روش
- بررسی استثنا
- ساختار بسته
- زبان و نسخه برنامه نویسی
- چارچوبها، ابزارها و کتابخانهها
- استانداردهای تست کد
- لایه های کد (کنترل کننده، سرویس، مخزن، دامنه و غیره)
هنگامی که در مورد قوانین کد خود به توافق رسیدید، می توانید کل تیم را برای بررسی آن و اطمینان از اینکه کد به خوبی نوشته شده و قابل استفاده مجدد است، مسئول نگه دارید. اگر توافق تیمی وجود نداشته باشد، هیچ راهی وجود ندارد که کد به یک استاندارد سالم و قابل استفاده مجدد نوشته شود.
API های خود را مستند کنید
هنگام ایجاد سرویسها و نمایش آنها بهعنوان یک API، باید API را مستند کنید تا درک و استفاده از آن برای توسعهدهندگان جدید آسان باشد.
APIها معمولاً با معماری میکروسرویس ها استفاده می شوند. در نتیجه، تیم های دیگری که اطلاعات زیادی در مورد پروژه شما ندارند باید بتوانند اسناد API شما را بخوانند و آن را درک کنند. اگر API به خوبی مستند نشده باشد، احتمال تکرار کد بیشتر است. توسعه دهندگان جدید احتمالاً یک روش API دیگر ایجاد خواهند کرد که روش موجود را کپی می کند.
بنابراین، مستندسازی API شما بسیار مهم است. در عین حال، استفاده بیش از حد از اسناد در کد ارزش چندانی ندارد. فقط کدهایی را مستند کنید که در API شما ارزشمند هستند. به عنوان مثال، عملیات تجاری در API، پارامترها، اشیاء برگشتی و غیره را توضیح دهید.
از قراردادهای نامگذاری کد استاندارد پیروی کنید
نامهای رمزی ساده و توصیفی به مخففهای مرموز ترجیح داده میشوند. وقتی نام اختصاری را در یک پایگاه کد ناآشنا می بینم، معمولاً معنی آن را نمی دانم.
بنابراین، به جای استفاده از مخفف Ctr
، Customer
را بنویسید. واضح و معنادار است. Ctr میتواند مخفف قرارداد، کنترل، مشتری باشد—معنای بسیاری دارد!
همچنین، از قراردادهای نامگذاری زبان برنامه نویسی خود استفاده کنید. به عنوان مثال، برای جاوا، قرارداد نامگذاری JavaBeans وجود دارد. این ساده است و هر توسعه دهنده جاوا باید آن را درک کند. در اینجا نحوه نامگذاری کلاس ها، متدها، متغیرها و بسته ها در جاوا آمده است:
- کلاس ها، PascalCase:
CustomerContract
- روش ها و متغیرها، camelCase:
customerContract
- بسته ها، همه حروف کوچک:
سرویس
کلاس ها و روش های منسجمی بنویسید
کد منسجم یک کار را به خوبی انجام می دهد. اگرچه نوشتن کلاسها و متدهای منسجم مفهومی ساده است، حتی توسعهدهندگان با تجربه آن را به خوبی دنبال نمیکنند. در نتیجه، آنها کلاس های فوق مسئولیت پذیر ایجاد می کنند، یعنی کلاس هایی که کارهای زیادی انجام می دهند. اینها گاهی اوقات به عنوان کلاس های خدا نیز شناخته می شوند.
برای اینکه کد خود را منسجم کنید، باید بدانید که چگونه آن را تجزیه کنید تا هر کلاس و متد یک کار را به خوبی انجام دهد. اگر روشی به نام saveCustomer
ایجاد می کنید، می خواهید این روش یک عمل داشته باشد: ذخیره یک مشتری. همچنین نباید مشتریان را بهروزرسانی و حذف کند.
به همین ترتیب، اگر کلاسی به نام CustomerService
داشته باشیم، باید فقط ویژگی هایی داشته باشد که متعلق به مشتری است. اگر متدی در کلاس CustomerService
داریم که عملیات را با دامنه محصول انجام می دهد، باید روش را به کلاس ProductService
منتقل کنیم.
به جای داشتن روشی که عملیات محصول را در کلاس CustomerService
انجام می دهد، می توانیم از ProductService
در کلاس CustomerService
استفاده کنیم و هر چیزی را فراخوانی کنیم. روشی که از آن نیاز داریم.
برای درک بهتر این مفهوم، ابتدا به مثالی از کلاسی نگاه می کنیم که منسجم نیست:
public class CustomerPurchaseService {
public void saveCustomerPurchase(CustomerPurchase customerPurchase) {
// Does operations with customer
registerProduct(customerPurchase.getProduct());
// update customer
// delete customer
}
private void registerProduct(Product product) {
// Performs logic for product in the domain of the customer…
}
}
بسیار خوب، پس مشکلات این کلاس چیست؟
- روش
saveCustomerPurchase
محصول را ثبت میکند و همچنین مشتری را بهروزرسانی و حذف میکند. این روش کارهای زیادی انجام می دهد. - پیدا کردن روش
registerProduct
دشوار است. به همین دلیل، احتمال زیادی وجود دارد که توسعهدهنده این روش را در صورت نیاز به چیزی شبیه به آن تکرار کند. - روش
registerProduct
در دامنه اشتباهی قرار دارد.CustomerPurchaseService
نباید محصولات را ثبت کند. - روش
saveCustomerPurchase
به جای استفاده از یک کلاس خارجی که عملیات محصول را انجام می دهد، یک روش خصوصی را فراخوانی می کند.
اکنون که میدانیم مشکل کد چیست، میتوانیم آن را بازنویسی کنیم تا منسجم شود. ما روش registerProduct
را به دامنه صحیح آن، ProductService
منتقل خواهیم کرد. این امر جستجو و استفاده مجدد کد را بسیار ساده تر می کند. همچنین، این روش در CustomerPurchaseService
گیر نمی کند:
public class CustomerPurchaseService {
private ProductService productService;
public CustomerPurchaseService(ProductService productService) {
this.productService = productService;
}
public void saveCustomerPurchase(CustomerPurchase customerPurchase) {
// Does operations with customer
productService.registerProduct(customerPurchase.getProduct());
}
}
public class ProductService {
public void registerProduct(Product product) {
// Performs logic for product in the domain of the customer…
}
}
در اینجا، saveCustomerPurchase
را مجبور کردهایم فقط یک کار را انجام دهد: صرفهجویی در خرید مشتری، نه چیز دیگری. ما همچنین مسئولیت registerProduct
را به کلاس ProductService
واگذار کردیم که هر دو کلاس را منسجم تر می کند. اکنون، کلاسها و متدهای آنها آنچه را که ما انتظار داریم انجام میدهند.
کلاس های خود را جدا کنید
کد بسیار جفت شده کدی است که وابستگی های زیادی دارد و حفظ کد را دشوارتر می کند. هر چه یک کلاس وابستگی های بیشتری (تعداد کلاس های تعریف شده) داشته باشد، جفت شدن آن بیشتر است.
جداسازی معماری نرم افزار
این مفهوم کوپلینگ در زمینه معماری نرم افزار نیز استفاده می شود. به عنوان مثال، معماری میکروسرویس ها نیز هدف جداسازی خدمات را دارد. یک میکروسرویس اگر به بسیاری از ریزسرویسهای دیگر متصل باشد، بسیار جفت میشود.
بهترین راه برای استفاده مجدد از کد این است که سیستم ها و کدها را تا حد امکان به یکدیگر وابسته کنند. یک سطح جفت مشخص همیشه وجود خواهد داشت زیرا خدمات و کد باید با هم ارتباط برقرار کنند. نکته کلیدی این است که آن خدمات را تا حد امکان مستقل کنید.
در اینجا مثالی از یک کلاس بسیار جفت شده آورده شده است:
public class CustomerOrderService {
private ProductService productService;
private OrderService orderService;
private CustomerPaymentRepository customerPaymentRepository;
private CustomerDiscountRepository customerDiscountRepository;
private CustomerContractRepository customerContractRepository;
private CustomerOrderRepository customerOrderRepository;
private CustomerGiftCardRepository customerGiftCardRepository;
// Other methods…
}
توجه داشته باشید که CustomerService
با بسیاری از کلاس های خدمات دیگر به شدت همراه است. داشتن وابستگی های زیاد به این معنی است که کلاس به خطوط کد زیادی نیاز دارد. این امر آزمایش کد و نگهداری آن را سخت می کند.
رویکرد بهتر این است که این کلاس را به سرویس هایی با وابستگی کمتر تقسیم کنید. بیایید با تقسیم کردن کلاس CustomerService
به سرویسهای جداگانه، اتصال را کاهش دهیم:
public class CustomerOrderService {
private OrderService orderService;
private CustomerPaymentService customerPaymentService;
private CustomerDiscountService customerDiscountService;
// Omitted other methods…
}
public class CustomerPaymentService {
private ProductService productService;
private CustomerPaymentRepository customerPaymentRepository;
private CustomerContractRepository customerContractRepository;
// Omitted other methods…
}
public class CustomerDiscountService {
private CustomerDiscountRepository customerDiscountRepository;
private CustomerGiftCardRepository customerGiftCardRepository;
// Omitted other methods…
}
پس از refactoring، CustomerService
و کلاسهای دیگر تست واحد بسیار آسانتر است، و همچنین نگهداری آنها آسانتر است. هرچه کلاس تخصصی تر و مختصرتر باشد، پیاده سازی ویژگی های جدید آسان تر است. اگر اشکالاتی وجود داشته باشد، رفع آنها آسانتر خواهد بود.
آن را جامد نگه دارید
SOLID مخفف است که نشان دهنده پنج اصل طراحی در برنامه نویسی شی گرا (OOP) است. هدف این اصول این است که سیستم های نرم افزاری قابل نگهداری تر، انعطاف پذیرتر و به راحتی قابل درک باشند. در اینجا توضیح مختصری درباره هر اصل آورده شده است:
- اصل مسئولیت واحد (SRP): یک کلاس باید یک مسئولیت یا هدف واحد داشته باشد و آن مسئولیت را در بر بگیرد. این اصل انسجام بالا را ارتقا میدهد و به تمرکز و مدیریت کلاسها کمک میکند.
- اصل باز-بسته (OCP): موجودیتهای نرمافزار (کلاسها، ماژولها، متدها و غیره) باید برای توسعه باز باشند اما برای اصلاح بسته باشند. شما باید کد خود را طوری طراحی کنید که به شما امکان دهد عملکردها یا رفتارهای جدیدی را بدون تغییر کد موجود، کاهش تأثیر تغییرات و ترویج استفاده مجدد از کد اضافه کنید.
- اصل جایگزینی لیسکوف (LSP): اشیاء یک سوپرکلاس باید با اشیاء زیر کلاسهای آن بدون تأثیر بر صحت برنامه قابل تعویض باشند. به عبارت دیگر، هر نمونه ای از یک کلاس پایه باید با هر نمونه ای از کلاس های مشتق شده آن جایگزین شود، و اطمینان حاصل شود که رفتار برنامه ثابت می ماند.
- اصل جداسازی رابط (ISP): کلاینت ها نباید مجبور شوند به واسط هایی که استفاده نمی کنند وابسته باشند. این اصل توصیه میکند که رابطهای بزرگ را به واسطهای کوچکتر و خاصتر تقسیم کنید تا مشتریان فقط به واسطهای مربوطه وابسته باشند. این امر اتصال شل را ترویج می کند و از وابستگی های غیر ضروری جلوگیری می کند.
- اصل وارونگی وابستگی (DIP): ماژول های سطح بالا نباید به ماژول های سطح پایین وابسته باشند. هر دو باید به انتزاعات بستگی داشته باشند. این اصل استفاده از انتزاعها (رابط یا کلاسهای انتزاعی) را برای جدا کردن ماژولهای سطح بالا از جزئیات پیادهسازی سطح پایین تشویق میکند. این ایده را ترویج میکند که کلاسها باید به انتزاعها به جای پیادهسازی عینی وابسته باشند، سیستم را انعطافپذیرتر میکند و آزمایش و نگهداری آسانتر را تسهیل میکند.
با پیروی از این اصول SOLID، توسعه دهندگان می توانند کدهای ماژولار، قابل نگهداری و توسعه پذیرتری ایجاد کنند. این اصول به دستیابی به کدی کمک میکند که درک، آزمایش و اصلاح آن آسانتر باشد و منجر به سیستمهای نرمافزاری قویتر و سازگارتر شود.
در صورت لزوم از الگوهای طراحی استفاده کنید
الگوهای طراحی توسط توسعه دهندگان باتجربه ای که موقعیت های کدنویسی زیادی را پشت سر گذاشته اند ایجاد شده اند. در صورت استفاده صحیح، الگوهای طراحی به استفاده مجدد از کد کمک می کنند.
درک الگوهای طراحی همچنین توانایی شما را در خواندن و درک کد بهبود میبخشد—حتی کدهای JDK زمانی واضحتر میشوند که بتوانید الگوی طراحی زیربنایی را ببینید.
اگرچه الگوهای طراحی قدرتمند هستند، هیچ الگوی طراحی یک گلوله نقره ای نیست. ما هنوز باید در استفاده از آنها بسیار مراقب باشیم. به عنوان مثال، استفاده از الگوی طراحی فقط به این دلیل که آن را می دانیم اشتباه است. استفاده از الگوی طراحی در موقعیت اشتباه، کد را پیچیده تر و نگهداری آن را دشوار می کند. با این حال، استفاده از یک الگوی طراحی برای استفاده مناسب، کد را برای توسعه انعطافپذیرتر میکند.
در اینجا خلاصه ای سریع از الگوهای طراحی در برنامه نویسی شی گرا آورده شده است:
- Singleton: اطمینان حاصل می کند که یک کلاس فقط یک نمونه دارد و دسترسی سراسری به آن را فراهم می کند.
- روش کارخانه: یک رابط برای ایجاد اشیا تعریف میکند، اما به کلاسهای فرعی اجازه میدهد تصمیم بگیرند که کدام کلاس را نمونهسازی کنند.
- کارخانه انتزاعی: یک رابط برای ایجاد خانواده های اشیاء مرتبط یا وابسته ارائه می دهد.
- Builder: ساخت اشیاء پیچیده را از نمایش آنها جدا می کند.
- نمونه اولیه: با شبیه سازی اشیاء موجود، اشیاء جدیدی ایجاد می کند.
- آداپتور: رابط یک کلاس را به رابط دیگری که مشتریان انتظار دارند تبدیل می کند.
- Decorator: به صورت پویا رفتار را به یک شی اضافه می کند.
- پراکسی: یک جانشین یا مکان نگهدار برای یک شی دیگر برای کنترل دسترسی به آن فراهم می کند.
- ترکیب: گروهی از اشیاء را به عنوان یک شی واحد در نظر می گیرد.
- Bridge: یک انتزاع را از اجرای آن جدا می کند.
پست های مرتبط
نحوه نوشتن کد جاوا قابل استفاده مجدد
نحوه نوشتن کد جاوا قابل استفاده مجدد
نحوه نوشتن کد جاوا قابل استفاده مجدد