Self-describing code is a practice in programming where the names of methods, functions, variables, and classes are chosen to be clear and descriptive. This means that the names themselves provide an understanding of what the code does without requiring additional comments or documentation.
Consider the task of writing a function to validate email addresses. A self-describing name for this function would be validateEmailAddress
. This name immediately informs the reader of its purpose.
def validateEmailAddress(email):
# Check if the email contains an '@' symbol
if '@' in email:
return True
return False
The primary purpose of self-describing code is to enhance code readability and maintainability. Here are several specific benefits:
- Improved Readability: When code is easy to read, it is easier to understand. Descriptive names act as documentation that explains what the code does.
- Easier Maintenance: When other developers (or even your future self) need to work on the code, they can quickly grasp the functionality without needing to decipher cryptic names or search for additional documentation.
- Reduced Need for Comments: While comments are useful, they can become outdated if not maintained properly. Self-describing names remain accurate as long as the code structure remains consistent with the names.
- Enhanced Collaboration: Clear code fosters better collaboration among team members, as everyone can understand and contribute to the codebase more effectively.
Use meaningful variable names that convey the purpose of the variable.
Poor Example:
x = 10
y = 20
z = x + y
Good Example:
numberOfApples = 10
numberOfOranges = 20
totalFruits = numberOfApples + numberOfOranges
In the good example, the variable names clearly indicate what each value represents, making the code easier to understand.
Name functions and methods based on the action they perform.
Poor Example:
def proc(data):
# process data
pass
Good Example:
def processData(data):
# process data
pass
The good example tells us that the function processes data, making the code more intuitive.
Class names should represent the objects or concepts they model.
Poor Example:
class D:
pass
Good Example:
class Document:
pass
The good example clearly indicates that the class represents a document.
Constants should be named to indicate their purpose and should be written in uppercase with words separated by underscores.
Poor Example:
pi = 3.14159
Good Example:
PI = 3.14159
// Function to fetch user data from an API
async function fetchUserData(userId) {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return data;
}
// Component to display user profile
function UserProfile({ user }) {
return (
<div className="user-profile">
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
</div>
);
}
def calculate_average(numbers):
"""
Calculate the average of a list of numbers.
Parameters:
numbers (list of float): A list of numbers.
Returns:
float: The average of the numbers.
"""
return sum(numbers) / len(numbers)
// Function to validate an email address
bool isValidEmail(String email) {
return RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(email);
}
// Widget to display a user's profile
class UserProfile extends StatelessWidget {
final String name;
final String email;
UserProfile({required this.name, required this.email});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(name, style: TextStyle(fontSize: 24)),
Text(email, style: TextStyle(fontSize: 16)),
],
);
}
}
- Definition: Place comments within the code to explain specific decisions, logic, or functions.
- Usage: Use inline comments to provide context or rationale for complex or non-obvious parts of the code.
- Balance: Avoid over-commenting; include enough to explain critical parts without cluttering the code.
Inline comments provide additional context where necessary. Avoid over-commenting; include enough to explain critical parts without cluttering the code.
async function fetchUserData(userId) {
// Fetch user data from the API
const response = await fetch(`/api/users/${userId}`);
// Parse the response as JSON
const data = await response.json();
return data;
}
def calculate_average(numbers):
"""
Calculate the average of a list of numbers.
"""
# Sum the numbers and divide by the count
return sum(numbers) / len(numbers)
bool isValidEmail(String email) {
// Regular expression to check if the email is valid
return RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(email);
}
class UserProfile extends StatelessWidget {
final String name;
final String email;
UserProfile({required this.name, required this.email});
@override
Widget build(BuildContext context) {
// Display the user's name and email
return Column(
children: [
Text(name, style: TextStyle(fontSize: 24)),
Text(email, style: TextStyle(fontSize: 16)),
],
);
}
}
- Definition: Use commit messages and pull request descriptions to document changes and reasons for those changes.
- Purpose: Provides a historical context and reasoning for changes, which is useful for tracking the evolution of the codebase.
Using commit messages and pull request descriptions to document changes and reasons for those changes provides historical context and rationale for changes.
- Next.js:
git commit -m "Add fetchUserData function to handle API requests"
- Python:
git commit -m "Implement calculate_average function to compute the average of a list"
- Flutter:
git commit -m "Create UserProfile widget to display user details"
- Next.js:
## Summary This PR adds a new function, `fetchUserData`, to fetch user data from the API. It also includes a `UserProfile` component to display the user's information. ## Changes - Added `fetchUserData` function in `utils/api.js` - Created `UserProfile` component in `components/UserProfile.js` ## Test Plan - Verified that the `fetchUserData` function correctly fetches data from the API. - Ensured that the `UserProfile` component displays the fetched data correctly.
- External Documentation
-
Definition: Create a comprehensive document (using tools like Google Docs) that describes the application's architecture, major functionalities, and design choices.
-
Structure:
- Introduction: Overview of the application and its purpose.
- Architecture: Detailed explanation of the system's architecture.
- Functionality: Breakdown of major functions or modules.
- Design Decisions: Explanation of why certain design choices were made, especially if they are complex or non-standard.
- Accessibility: Ensure this document is easily accessible to all team members.
-
Example: For a sample of such documentation, see this Google Docs Example.
-
Creating a comprehensive document (using tools like Google Docs) that describes the application's architecture, major functionalities, and design choices ensures that your code remains maintainable, understandable, and easier to work with for current and future developers.
Project Documentation
Overview
This project is a user management application built with Next.js. It allows administrators to manage user profiles.
Architecture
- Pages: Contains the main application pages.
- Components: Reusable UI components.
- Utils: Utility functions for API calls and data processing.
Major Functionalities
Fetch User Data
The `fetchUserData` function in `utils/api.js` is responsible for fetching user data from the API. It takes a `userId` as a parameter and returns the user data in JSON format.
Display User Profile
The `UserProfile` component in `components/UserProfile.js` displays the user's name and email. It receives a `user` object as a prop.
Design Decisions
- API Structure: The decision to use `/api/users/:id` was made to keep the API endpoint RESTful.
- Component Design: The `UserProfile` component was designed as a functional component to simplify state management.
Example: For a sample of such documentation, see this Google Docs Example and this YouTube Video.
###################################################################################################
کد خودتوضیحی یک روش در برنامهنویسی است که در آن نامهای متدها، توابع، متغیرها و کلاسها به صورت واضح و توصیفی انتخاب میشوند. این بدان معناست که نامها خودشان توضیح میدهند که کد چه کاری انجام میدهد، بدون نیاز به توضیحات یا مستندات اضافی.
وظیفه نوشتن یک تابع برای اعتبارسنجی آدرسهای ایمیل را در نظر بگیرید. یک نام خودتوضیحی برای این تابع میتواند validateEmailAddress
باشد. این نام بلافاصله هدف آن را به خواننده اطلاع میدهد.
def validateEmailAddress(email):
# Check if the email contains an '@' symbol
if '@' in email:
return True
return False
هدف اصلی کد خودتوضیحی افزایش خوانایی و قابلیت نگهداری کد است. در اینجا چندین مزیت خاص آورده شده است:
۱. بهبود خوانایی: وقتی کد خواندنش آسان باشد، درک آن نیز آسانتر است. نامهای توصیفی مانند مستندات عمل میکنند که توضیح میدهند کد چه کاری انجام میدهد.
۲. نگهداری آسانتر: وقتی دیگر توسعهدهندگان (یا حتی خود شما در آینده) نیاز به کار روی کد دارند، میتوانند به سرعت عملکرد را بدون نیاز به رمزگشایی نامهای مبهم یا جستجو برای مستندات اضافی درک کنند.
۳. نیاز کمتر به توضیحات: در حالی که توضیحات مفید هستند، اگر به درستی نگهداری نشوند میتوانند قدیمی شوند. نامهای خودتوضیحی تا زمانی که ساختار کد با نامها سازگار باشد، دقیق باقی میمانند.
۴. افزایش همکاری: کد واضح همکاری بهتری بین اعضای تیم ایجاد میکند، زیرا همه میتوانند کد را درک کرده و به طور موثر به کدبیس کمک کنند.
از نامهای متغیر معنیدار استفاده کنید که هدف متغیر را نشان میدهند.
مثال بد:
x = 10
y = 20
z = x + y
مثال خوب:
numberOfApples = 10
numberOfOranges = 20
totalFruits = numberOfApples + numberOfOranges
در مثال خوب، نامهای متغیر به وضوح نشان میدهند که هر مقدار چه چیزی را نمایندگی میکند، و این باعث میشود کد راحتتر درک شود.
نام توابع و متدها را بر اساس عملی که انجام میدهند انتخاب کنید.
مثال بد:
def proc(data):
# process data
pass
مثال خوب:
def processData(data):
# process data
pass
مثال خوب به ما میگوید که تابع دادهها را پردازش میکند، و این باعث میشود کد بیشتر قابل درک باشد.
نام کلاسها باید نمایانگر اشیاء یا مفاهیمی باشند که مدل میکنند.
مثال بد:
class D:
pass
مثال خوب:
class Document:
pass
مثال خوب به وضوح نشان میدهد که کلاس نمایانگر یک سند است.
ثوابت باید طوری نامگذاری شوند که هدف آنها را نشان دهند و باید با حروف بزرگ و کلمات جدا شده با زیرخط نوشته شوند.
مثال بد:
pi = 3.14159
مثال خوب:
PI = 3.14159
// Function to fetch user data from an API
async function fetchUserData(userId) {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return data;
}
// Component to display user profile
function UserProfile({ user }) {
return (
<div className="user-profile">
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
</div>
);
}
def calculate_average(numbers):
"""
Calculate the average of a list of numbers.
Parameters:
numbers (list of float): A list of numbers.
Returns:
float: The average of the numbers.
"""
return sum(numbers) / len(numbers)
// Function to validate an email address
bool isValidEmail(String email) {
return RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(email);
}
// Widget to display a user's profile
class UserProfile extends StatelessWidget {
final String name;
final String email;
UserProfile({required this.name, required this.email});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(name, style: TextStyle(fontSize: 24)),
Text(email, style: TextStyle(fontSize: 16)),
],
);
}
}
- تعریف: قرار دادن توضیحات درون کد برای توضیح تصمیمات خاص، منطق یا توابع.
- استفاده: از توضیحات خطی برای ارائه زمینه یا دلایل برای بخشهای پیچیده یا غیر واضح کد استفاده کنید.
- تعادل: از توضیح بیش از حد پرهیز کنید؛ به اندازه کافی توضیحات برای توضیح قسمتهای بحرانی بدون ایجاد شلوغی در کد اضافه کنید.
توضیحات خطی در جایی که لازم است زمینه اضافی فراهم میکنند. از توضیح بیش از حد پرهیز کنید؛ به اندازه کافی توضیحات برای توضیح قسمتهای بحرانی بدون ایجاد شلوغی در کد اضافه کنید.
async function fetchUserData(userId) {
// Fetch user data from the API
const response = await fetch(`/api/users/${userId}`);
// Parse the response as JSON
const data = await response.json();
return data;
}
def calculate_average(numbers):
"""
Calculate the average of a list of numbers.
"""
// Sum the numbers and divide by the count
return sum(numbers) / len(numbers)
bool isValidEmail(String email) {
// Regular expression to check if the email is valid
return RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(email);
}
class UserProfile extends StatelessWidget {
final String name;
final String email;
UserProfile({required this.name, required this.email});
@override
Widget build(BuildContext context) {
// Display the user's name and email
return Column(
children: [
Text(name, style: TextStyle(fontSize: 24)),
Text(email, style: TextStyle(fontSize: 16)),
],
);
}
}
- تعریف: استفاده از پیامهای کامیت و توضیحات درخواستهای کششی برای مستند کردن تغییرات و دلایل آنها.
- هدف: فراهم کردن زمینه تاریخی و دلیل برای تغییرات، که برای ردیابی تکامل کدبیس مفید است.
استفاده از پیامهای کامیت و توضیحات درخواستهای کششی برای مستند کردن تغییرات و دلایل آنها زمینه تاریخی و دلیل برای تغییرات فراهم میکند.
- Next.js:
git commit -m "Add fetchUserData function to handle API requests"
- Python:
git commit -m "Implement calculate_average function to compute the average of a list"
- Flutter:
git commit -m "Create UserProfile widget to display user details"
- Next.js:
## Summary This PR adds a new function, `fetchUserData`, to fetch user data from the API. It also includes a `UserProfile` component to display the user's information. ## Changes - Added `fetchUserData` function in `utils/api.js` - Created `UserProfile` component in `components/UserProfile.js` ## Test Plan - Verified that the `fetchUserData` function correctly fetches data from the API. - Ensured that the `UserProfile` component displays the fetched data correctly.
- مستندات خارجی
-
تعریف: ایجاد یک سند جامع (با استفاده از ابزارهایی مانند Google Docs) که معماری برنامه، عملکردهای اصلی و انتخابهای طراحی را توصیف میکند.
-
ساختار:
- مقدمه: نمای کلی از برنامه و هدف آن.
- معماری: توضیح دقیق معماری سیستم.
- عملکرد: تجزیه و تحلیل عملکردهای اصلی یا ماژولها.
- تصمیمات طراحی: توضیح اینکه چرا انتخابهای طراحی خاصی انجام شدهاند، به ویژه اگر پیچیده یا غیر معمول باشند.
- دسترسی: اطمینان حاصل کنید که این سند به راحتی برای همه اعضای تیم قابل دسترسی است.
-
مثال: برای نمونهای از چنین مستنداتی، این مثال Google Docs را ببینید.
-
ایجاد یک سند جامع (با استفاده از ابزارهایی مانند Google Docs) که معماری برنامه، عملکردهای اصلی و انتخابهای طراحی را توصیف میکند، اطمینان میدهد که کد شما قابل نگهداری، قابل فهم و برای توسعهدهندگان فعلی و آینده راحتتر کار خواهد بود.
Project Documentation
Overview
This project is a user management application built with Next.js. It allows administrators to manage user profiles.
Architecture
- Pages: Contains the main application pages.
- Components: Reusable UI components.
- Utils: Utility functions for API calls and data processing.
Major Functionalities
Fetch User Data
The `fetchUserData` function in `utils/api.js` is responsible for fetching user data from the API. It takes a `userId` as a parameter and returns the user data in JSON format.
Display User Profile
The `UserProfile` component in `components/UserProfile.js` displays the user's name and email. It receives a `user` object as a prop.
Design Decisions
- API Structure: The decision to use `/api/users/:id` was made to keep the API endpoint RESTful.
- Component Design: The `UserProfile` component was designed as a functional component to simplify state management.
Example: For a sample of such documentation, see this Google Docs Example and this YouTube Video.