I think those two concepts (maybe call them philosophy) are the most useful techniques in Object-Oriented Design.
- DRY: Extract repeated or similar functions and reuse them.
- Single Responsibility: Keep your small chunk of code simple.
I would like to add one more thing that I usually call three of them "Good Code Smell"
- Take advantage of variables.
We normally write code directly like this:
function checkScore {
if (score > 50) {
// do something
}
}
When the condition becomes complicated:
function checkScore {
if (score > 50 && score <= 100) {
// do something
}
}
More complicated:
function checkScore {
if (score > 50 && score <= 100 && seconds > 60 && seconds <= 120) {
// do something
}
}
Well, all of them look ok, but how about this one:
function checkTenPercentOff() {
if (
// check qualified user
user.title == 'Gold Member' && user.points > 1000 &&
// check cart is not empty
cartItems != null && cartItems != undefined && cartItems.length > 0 &&
// check each item's quantity
checkQuantity(cartItems) &&
// check special sales period
now > new Date('2019-09-01T00:00:00') && now <= new Date('2019-12-31T00:00:00')
) {
// do 10% off for the user
}
}
This is a monster if statement although it may still simple compared with real requirements from an SRS.
Now, we can take advantage of variable names.
function checkTenPercentOff() {
// Look, we even don't need comments if we have good variable names
var isQualifiedUser = user.title == 'Gold Member' && user.points > 1000;
var isNotEmptyCart = cartItems != null && cartItems != undefined && cartItems.length > 0;
var allItemsHaveQuantity = checkQuantity(cartItems);
var isSpecialSalesPeriod = now > Date('2019-09-01T00:00:00') && now <= new Date('2019-12-31T00:00:00');
var isQualifiedForTenPercentOff =
isQualifiedUser &&
isNotEmptyCart &&
allItemsHaveQuantity &&
isSpecialSalesPeriod;
if (isQualifiedForTenPercentOff) {
// do 10% off for the user
}
}
It looks much clear and easy to read now.
Remember the DRY and Single Responsibility? How about this:
// extract variables as parameters, then you don't hard-code a function.
function checkQualifiedUser(title, points) {
var isQualifiedUser = user.title == title && user.points > points;
return isQualifiedUser;
}
function checkNotEmptyCart(cartItems) {
var isNotEmptyCart = cartItems != null && cartItems != undefined && cartItems.length > 0;
return isNotEmptyCart;
}
function checkAllItemsHaveQuantity(cartItems) {
var allItemsHaveQuantity = checkQuantity(cartItems);
return allItemsHaveQuantity;
}
function checkSpecialSalesPeriod(startDate, endDate) {
var isSpecialSalesPeriod = now > startDate && now <= endDate;
return isSpecialSalesPeriod;
}
function checkTenPercentOff() {
var isQualifiedForTenPercentOff =
checkQualifiedUser('Gold Member', 1000) &&
checkNotEmptyCart(cartItems) &&
checkAllItemsHaveQuantity(cartItems) &&
checkSpecialSalesPeriod(new Date('2019-09-01T00:00:00'), new Date('2019-12-31T00:00:00'));
if (isQualifiedForTenPercentOff) {
// do 10% off for the user
}
}
function checkFifteenPercentOff() {
var isQualifiedForFifteenPercentOff =
checkQualifiedUser('Diamond Member', 2000) &&
checkNotEmptyCart(cartItems) &&
checkAllItemsHaveQuantity(cartItems) &&
checkSpecialSalesPeriod(new Date('2020-01-01T00:00:00'), new Date('2020-06-31T00:00:00'));
if (isQualifiedForFifteenPercentOff) {
// do 15% off for the user
}
}
Now, we have reusable(DRY) and short(Single Responsibility) functions and clear variable names(Take advantage of variables)

