Mbinu Zangu Bora – Jumla
1. Maoni ndani ya msimbo – laana na baraka
Maoni mazuri ni sanaa. Yakiandikwa kwa busara ni neema – lakini mara nyingi ni bure tu.
Msimbo unaojieleza wenyewe (self-documenting code) haumaanishi “hakuna maoni”. Msimbo wenyewe unapaswa kueleza jinsi kitu kinavyofanyika kadiri iwezekanavyo; maoni yanaongeza kwa nini, masharti yasiyo dhahiri na mkataba wa API.
Ifuatayo ni baadhi ya mifano ya msimbo unaojieleza wenyewe, pamoja na maoni mazuri na mabaya.
Hoja inayosikika mara nyingi ni kwamba maoni hupitwa na wakati kwa urahisi. Ukweli ni kwamba tatizo hili linahusu pia majina ya vigeu na mbinu kwa kiwango kilekile!
Lo – usifanye hivi kamwe:
int age = 32; // set the value of the age integer to 32
Msimbo unaojieleza: majina yenye maana ya vigeu ni nusu ya kazi
Mbaya:
var dateTime = DateTimeUtil.getNow();
Nzuri:
var now = DateTimeUtil.getNow();
Mfano mwingine:
Mbaya:
User user = this.getBruce();
Mbaya:
// testing user without permission
User user = this.getBruce();
Nzuri:
User userWithoutPermission = this.getBruce();
Msimbo unaojieleza: majina yenye maana ya mbinu
Mbaya:
public String sanitizeInput(String input) {
// replace underscore with spaces
return input.replaceAll("_", " ");
}
Nzuri:
public String replaceUnderscoreWithSpaces(String input) {
return input.replaceAll("_", " ");
}
Msimbo unaojieleza: mbinu za faragha (private)
Mbaya: Mbinu hii inamlazimisha msomaji kufumbua uthibitishaji, hesabu na kanuni ya biashara kwa wakati mmoja.
public Invoice createInvoice(Order order, Customer customer) {
if (order.items().isEmpty()) {
throw new IllegalArgumentException("Order needs at least one item");
}
BigDecimal subtotal = order.items().stream()
.map(item -> item.unitPrice().multiply(BigDecimal.valueOf(item.quantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal discount = customer.isPremium()
? subtotal.multiply(new BigDecimal("0.10"))
: BigDecimal.ZERO;
return new Invoice(order.id(), subtotal, discount, subtotal.subtract(discount));
}
Nzuri: Mbinu ya umma inasimulia mtiririko. Mbinu za faragha zisizo na hali (stateless) zinataja kila nia kwa jina na kuonyesha utegemezi wake kupitia vigezo na thamani zinazorudishwa.
public Invoice createInvoice(Order order, Customer customer) {
requireItems(order);
BigDecimal subtotal = calculateSubtotal(order.items());
BigDecimal discount = loyaltyDiscountFor(customer, subtotal);
return invoiceFor(order, subtotal, discount);
}
private static void requireItems(Order order) {
if (order.items().isEmpty()) {
throw new IllegalArgumentException("Order needs at least one item");
}
}
private static BigDecimal calculateSubtotal(List<OrderItem> items) {
return items.stream()
.map(item -> item.unitPrice().multiply(BigDecimal.valueOf(item.quantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private static BigDecimal loyaltyDiscountFor(Customer customer, BigDecimal subtotal) {
return customer.isPremium()
? subtotal.multiply(new BigDecimal("0.10"))
: BigDecimal.ZERO;
}
private static Invoice invoiceFor(
Order order,
BigDecimal subtotal,
BigDecimal discount
) {
return new Invoice(order.id(), subtotal, discount, subtotal.subtract(discount));
}
Si kila mstari unahitaji mbinu yake. Kinachotolewa ni wazo moja kamili linaloweza kupewa jina sahihi. Majina kama processData() au handleStuff() hayaleti faida yoyote.
Kanuni ya jumla: eleza kwa nini jambo linatokea, si nini kinatokea
Ni wazi nini kinatokea hapa:
public Duration retryDelay(int retryCount) {
long seconds = Math.min(1L << retryCount, 60);
return Duration.ofSeconds(seconds);
}
Lakini kwa nini kinatokea?
Bora zaidi:
public Duration retryDelay(int retryCount) {
// Cap the delay so an outage never blocks queued jobs for more than one minute.
long seconds = Math.min(1L << retryCount, 60);
return Duration.ofSeconds(seconds);
}
Mfano mwingine kutoka kwa mradi halisi. Hapa kuna mbinu za kuonyesha na kuficha kiashiria cha upakiaji cha Ajax. Lakini kuna mbinu nne, na sababu yake haieleweki mara moja:
function showAjaxLoader() {
$('.layout-ajax-loader').children().first().show();
}
function hideAjaxLoader() {
$('.layout-ajax-loader').children().first().hide();
}
function suppressAjaxLoader() {
getOnlyElementByClassOrNull('layout-ajax-loader').style.display = 'none';
}
function releaseAjaxLoader() {
getOnlyElementByClassOrNull('layout-ajax-loader').style.display = '';
}
Mbinu hizi zinaonekana kufanana sana, na zote zinaonekana kubadilisha uonekanaji kupitia CSS kwa namna fulani. Kwa maoni mafupi, matumizi yake yanakuwa wazi mara moja:
showAjaxLoader: function() {
$('.layout-ajax-loader').children().first().show();
},
hideAjaxLoader: function() {
$('.layout-ajax-loader').children().first().hide();
},
// take the control from primefaces and don't allow the spinner to show, no matter what
suppressAjaxLoader: function() {
getOnlyElementByClassOrNull('layout-ajax-loader').style.display = 'none';
},
// reset the state after hiding, to give the control back to primefaces
releaseAjaxLoader: function() {
getOnlyElementByClassOrNull('layout-ajax-loader').style.display = '';
},
Mfano mwingine:
Mbaya:
/**
* Sets the tool tip text.
*
* @param text the text of the tool tip
*/
public void setToolTipText(String text) {}
Nzuri:
/**
* Registers the text to display in a tool tip. The text
* displays when the cursor lingers over the component.
*
* @param text the string to display. If the text is null,
* the tool tip is turned off for this component.
*/
public void setToolTipText(String text) {}
Mjadala katika warsha ya 2021-06-21: Wasanidi wote walikubaliana kwamba kwa ujumla Javadoc inapaswa kuepukwa (jinamizi la vigezo, hupitwa na wakati kila mara na si rahisi kuidumisha) na itumike tu pale ambapo kigezo kinahitaji kweli maelezo zaidi, au pale ambapo vinginevyo ingebidi msomaji asome mbinu nzima ndefu.
Isipokuwa kwa kanuni ya jumla: eleza nini kinatokea – hapa inashauriwa
Pale ambapo inarahisisha usomaji kwa kiasi kikubwa, kwa sababu vinginevyo msimbo haueleweki:
let isAlwaysAllowedKey = (
e.which === 8 || /* BACKSPACE */
e.which === 35 || /* END */
e.which === 36 || /* HOME */
e.which === 37 || /* LEFT */
e.which === 38 || /* UP */
e.which === 39 || /* RIGHT*/
e.which === 40 || /* DOWN */
e.which === 46 || /* DEL*/
e.ctrlKey === true && e.which === 65 || /* CTRL + A */
e.ctrlKey === true && e.which === 88 || /* CTRL + X */
e.ctrlKey === true && e.which === 67 || /* CTRL + C */
e.ctrlKey === true && e.which === 90 /* CTRL + Z */
)
Maoni – matusi ndani ya msimbo wa kernel ya Linux
Mwisho, kisa cha kuchekesha kutoka kernel ya Linux – idadi ya matusi yote ndani ya msimbo wake chanzo:
https://www.vidarholen.net/contents/wordcount/#fuck*,shit*,damn*,idiot*,retard*
Furahia kuandika maoni!
2. Mbinu za faragha ndani ya taratibu kubwa za programu ni hatari
Tahadhari! Katika ulimwengu wa leo wa programu zinazolenga vitu (object-oriented), daima kuna mbinu nyingi za faragha. Kwa kawaida hili si tatizo. Linakuwa tatizo tu pale mbinu hizi zinapofikia sehemu (fields), yaani hali (state), na zikiwa ndani ya taratibu kubwa. Mbinu ndogo kama hizi zinapaswa kuwa private na zisizo na hali (stateless). Vinginevyo, zikiitwa peke yake mara nyingi husababisha matatizo, kwa sababu wasanidi wengine watapata wazo la kuita mbinu ndogo hiyo moja kwa moja. Hali zisizo halali ni mojawapo ya sababu kuu za hitilafu. Kuna makala ya kuvutia kuhusu hili, inayotokana na kauli kadhaa za John Carmack (id Software, Doom): katika programu ambazo msimbo wake lazima uwe imara sana (kwa mfano safari za anga za juu), taratibu ndogo (subroutines) mara nyingi hupigwa marufuku, jambo linalofanya msimbo utabirike zaidi: http://number-none.com/blow/john_carmack_on_inlined_code.html
Kisa hiki kinahusika kwa kiasi tu na ulimwengu wa kisasa wa Java/Spring usio na hali, lakini bado ni chakula kizuri cha fikra.