Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//--------------------------------------------------------------------------------------
// 3. Function - Hàm
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
// Tránh side effects
// Bad
// Global variable referenced by following function.
// If we had another function that used this name, now it'd be an array and it could break it.
var name = 'Ryan McDermott';
public string SplitIntoFirstAndLastName()
{
return name.Split(" ");
}
SplitIntoFirstAndLastName();
Console.PrintLine(name); // ['Ryan', 'McDermott'];
// Good
public string SplitIntoFirstAndLastName(string name)
{
return name.Split(" ");
}
var name = 'Ryan McDermott';
var newName = SplitIntoFirstAndLastName(name);
Console.PrintLine(name); // 'Ryan McDermott';
Console.PrintLine(newName); // ['Ryan', 'McDermott'];
//--------------------------------------------------------------------------------------
// Tránh điều kiện negative false
// Bad
public bool IsDOMNodeNotPresent(string node)
{
// ...
}
if (!IsDOMNodeNotPresent(node))
{
// ...
}
// Good
public bool IsDOMNodePresent(string node)
{
// ...
}
if (IsDOMNodePresent(node))
{
// ...
}
//--------------------------------------------------------------------------------------
// Hạn chế dùng điều kiện mà thay vào đó hãy dùng kế thừa
// Bad
class Airplane
{
// ...
public double GetCruisingAltitude()
{
switch (_type)
{
case '777':
return GetMaxAltitude() - GetPassengerCount();
case 'Air Force One':
return GetMaxAltitude();
case 'Cessna':
return GetMaxAltitude() - GetFuelExpenditure();
}
}
}
// Good
interface IAirplane
{
// ...
double GetCruisingAltitude();
}
class Boeing777 : IAirplane
{
// ...
public double GetCruisingAltitude()
{
return GetMaxAltitude() - GetPassengerCount();
}
}
class AirForceOne : IAirplane
{
// ...
public double GetCruisingAltitude()
{
return GetMaxAltitude();
}
}
class Cessna : IAirplane
{
// ...
public double GetCruisingAltitude()
{
return GetMaxAltitude() - GetFuelExpenditure();
}
}
//--------------------------------------------------------------------------------------
// Tránh kiểm tra kiểu dữ liệu
// Bad
public Path TravelToTexas(object vehicle)
{
if (vehicle.GetType() == typeof(Bicycle))
{
(vehicle as Bicycle).PeddleTo(new Location("texas"));
}
else if (vehicle.GetType() == typeof(Car))
{
(vehicle as Car).DriveTo(new Location("texas"));
}
}
public int Combine(dynamic val1, dynamic val2)
{
int value;
if (!int.TryParse(val1, out value) || !int.TryParse(val2, out value))
{
throw new Exception('Must be of type Number');
}
return val1 + val2;
}
// Good
public Path TravelToTexas(Traveler vehicle)
{
vehicle.TravelTo(new Location("texas"));
}
// pattern matching
public Path TravelToTexas(object vehicle)
{
if (vehicle is Bicycle bicycle)
{
bicycle.PeddleTo(new Location("texas"));
}
else if (vehicle is Car car)
{
car.DriveTo(new Location("texas"));
}
}
public int Combine(int val1, int val2)
{
return val1 + val2;
}
//--------------------------------------------------------------------------------------
// Tránh đặt các cờ kiểu bool trong parameters
// Bad
public void CreateFile(string name, bool temp = false)
{
if (temp)
{
Touch("./temp/" + name);
}
else
{
Touch(name);
}
}
// Good
public void CreateFile(string name)
{
Touch(name);
}
public void CreateTempFile(string name)
{
Touch("./temp/" + name);
}
//--------------------------------------------------------------------------------------
// Không được write vào các hàm toàn cục
// Bad
public string[] Config()
{
return [
"foo" => "bar",
]
}
// Good
class Configuration
{
private string[] _configuration = [];
public Configuration(string[] configuration)
{
_configuration = configuration;
}
public string[] Get(string key)
{
return (_configuration[key]!= null) ? _configuration[key] : null;
}
}
// Load configuration and create instance of Configuration class
var configuration = new Configuration(new string[] {
"foo" => "bar",
});
//--------------------------------------------------------------------------------------
// Hạn chế sử dụng Singleton thay vào đó hãy dùng options
// Bad
class DBConnection
{
private static DBConnection _instance;
private DBConnection()
{
// ...
}
public static GetInstance()
{
if (_instance == null)
{
_instance = new DBConnection();
}
return _instance;
}
// ...
}
var singleton = DBConnection.GetInstance();
// Good
class DBConnection
{
public DBConnection(IOptions<DbConnectionOption> options)
{
// ...
}
// ...
}
// Create instance of DBConnection class and configure it with Option pattern.
var options = <resolve from IOC>;
var connection = new DBConnection(options);
//--------------------------------------------------------------------------------------
// Nên sử dụng tối đa 2 parameters cho một hàm
// Bad
public void CreateMenu(string title, string body, string buttonText, bool cancellable)
{
// ...
}
// Good
pubic class MenuConfig
{
public string Title { get; set; }
public string Body { get; set; }
public string ButtonText { get; set; }
public bool Cancellable { get; set; }
}
var config = new MenuConfig
{
Title = "Foo",
Body = "Bar",
ButtonText = "Baz",
Cancellable = true
};
public void CreateMenu(MenuConfig config)
{
// ...
}
//--------------------------------------------------------------------------------------
// Một hàm nên và chỉ nên làm một nhiệm vụ duy nhất
// Bad
public void SendEmailToListOfClients(string[] clients)
{
foreach (var client in clients)
{
var clientRecord = db.Find(client);
if (clientRecord.IsActive())
{
Email(client);
}
}
}
// Good
public void SendEmailToListOfClients(string[] clients)
{
var activeClients = GetActiveClients(clients);
// Do some logic
}
public List<Client> GetActiveClients(string[] clients)
{
return db.Find(clients).Where(s => s.Status == "Active");
}
//--------------------------------------------------------------------------------------
// Đặt tên hàm theo mục đích rõ ràng
// Bad
public class Email
{
//...
public void Handle()
{
SendMail(this._to, this._subject, this._body);
}
}
var message = new Email(...);
// What is this? A handle for the message? Are we writing to a file now?
message.Handle();
// Good
public class Email
{
//...
public void Send()
{
SendMail(this._to, this._subject, this._body);
}
}
var message = new Email(...);
// Clear and obvious
message.Send();
//--------------------------------------------------------------------------------------
// Functions should only be one level of abstraction
// Bad
public string ParseBetterJSAlternative(string code)
{
var regexes = [
// ...
];
var statements = explode(" ", code);
var tokens = new string[] {};
foreach (var regex in regexes)
{
foreach (var statement in statements)
{
// ...
}
}
var ast = new string[] {};
foreach (var token in tokens)
{
// lex...
}
foreach (var node in ast)
{
// parse...
}
}
// Good
class Tokenizer
{
public string Tokenize(string code)
{
var regexes = new string[] {
// ...
};
var statements = explode(" ", code);
var tokens = new string[] {};
foreach (var regex in regexes)
{
foreach (var statement in statements)
{
tokens[] = /* ... */;
}
}
return tokens;
}
}
class Lexer
{
public string Lexify(string[] tokens)
{
var ast = new[] {};
foreach (var token in tokens)
{
ast[] = /* ... */;
}
return ast;
}
}
class BetterJSAlternative
{
private string _tokenizer;
private string _lexer;
public BetterJSAlternative(Tokenizer tokenizer, Lexer lexer)
{
_tokenizer = tokenizer;
_lexer = lexer;
}
public string Parse(string code)
{
var tokens = _tokenizer.Tokenize(code);
var ast = _lexer.Lexify(tokens);
foreach (var node in ast)
{
// parse...
}
}
}
//--------------------------------------------------------------------------------------
// Các hàm callers và callees nên đặt gần nhau
// Bad
class PerformanceReview
{
private readonly Employee _employee;
public PerformanceReview(Employee employee)
{
_employee = employee;
}
private IEnumerable<PeersData> LookupPeers()
{
return db.lookup(_employee, 'peers');
}
private ManagerData LookupManager()
{
return db.lookup(_employee, 'manager');
}
private IEnumerable<PeerReviews> GetPeerReviews()
{
var peers = LookupPeers();
// ...
}
public PerfReviewData PerfReview()
{
GetPeerReviews();
GetManagerReview();
GetSelfReview();
}
public ManagerData GetManagerReview()
{
var manager = LookupManager();
}
public EmployeeData GetSelfReview()
{
// ...
}
}
var review = new PerformanceReview(employee);
review.PerfReview();
// Good
class PerformanceReview
{
private readonly Employee _employee;
public PerformanceReview(Employee employee)
{
_employee = employee;
}
public PerfReviewData PerfReview()
{
GetPeerReviews();
GetManagerReview();
GetSelfReview();
}
private IEnumerable<PeerReviews> GetPeerReviews()
{
var peers = LookupPeers();
// ...
}
private IEnumerable<PeersData> LookupPeers()
{
return db.lookup(_employee, 'peers');
}
private ManagerData GetManagerReview()
{
var manager = LookupManager();
return manager;
}
private ManagerData LookupManager()
{
return db.lookup(_employee, 'manager');
}
private EmployeeData GetSelfReview()
{
// ...
}
}
var review = new PerformanceReview(employee);
review.PerfReview();
//--------------------------------------------------------------------------------------
// Nên gom các biểu thức điều kiện và tách thành hàm riêng
// Bad
if (article.state == "published")
{
// ...
}
// Good
if (article.IsPublished())
{
// ...
}
//--------------------------------------------------------------------------------------
// Xóa hết các code không dùng
// Bad
public void OldRequestModule(string url)
{
// ...
}
public void NewRequestModule(string url)
{
// ...
}
var request = NewRequestModule(requestUrl);
InventoryTracker("apples", request, "www.inventory-awesome.io");
// Good
public void RequestModule(string url)
{
// ...
}
var request = RequestModule(requestUrl);
InventoryTracker("apples", request, "www.inventory-awesome.io");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment