-
Notifications
You must be signed in to change notification settings - Fork 14
Description
We should have a clear code style. This will allow me to inspect the code easier. The most important goal of the code style is to increase code readability.
- line width 120 characters (already done)
- indentation 2 characters or 4 in same cases (in change code indentation to two spaces per indent #351)
- Variable names:
- Use abbreviations aggressively if the meaning remains clear. For example,
generalMessageDetailscould be namedmsgDetails, as Msg is clear to mean Message. Same with Forward -> Fwd, Directory -> Dir, Reference -> Ref, Constant -> Const, Application -> App, Original -> Orig, Generate -> Gen, Command -> Cmd, Attribute -> Attr, Property -> Prop, Destination -> Dest, Connection -> Conn, Database -> Db, Credentials -> Creds, Account -> Acct, FlowCrypt -> Fc, Session -> Sess, Option -> Opt. But make sure not to shorten less common words that could be confused. For example,Connection -> Connbut leaveConnectas full word. Same withOptional, etc. - Skip words that do not add a meaningful distinction. generalMsgDetails -> msgDetails, msgDaoSource -> msgDao
- Use abbreviations aggressively if the meaning remains clear. For example,
- English language improvements:
isat the beginning should generally follow withingoredif there is a verb at the end:isThreadAlreadyWork()->isThreadAlreadyWorking(). But even better,isThreadBusy(). AlsoisDebugEnable->isDebugEnabledifNeedshould be spelled asifNeeded.WithOutshould be spelled asWithout,DataBaseshould be spelled asDatabase, but even betterDb
- Use
efor Exception name when catching, eg} catch (MessagingException e) {, but only if there is only one level of exception catching (no nested try/catch within each other). When you have nested catch/try blocks, give exceptions meaningful names (noteande1!), eg:
// this is ok
try {
callSomeApi();
} catch (MessagingException e) {
showRetryButton(e);
}
// this is ok
try {
try {
Info info = getInfoFromDb();
} catch (DbCorruptedException dbError) {
reportToAcra(dbError);
renderError(dbError)
return;
}
callSomeApi();
} catch (MessagingException msgError) {
renderRetryButton(msgError);
}
// this is NOT ok
try {
try {
Info info = getInfoFromDb();
} catch (DbCorruptedException e) {
reportToAcra(e);
renderError(e)
return;
}
callSomeApi();
} catch (MessagingException e1) {
renderRetryButton(e1);
}-
Avoid
Forif that can make the name shorter.getSessionForAccountDao->getAccountDaoSession. (It could be shortened further asgetAcctDaoSess) -
Maximum 8 nested block indents, except when the lines are very short and simple. Create a new method and call it if nested blocks get too deep. Eg this is not good (11 indents).
public LoaderResult loadInBackground() {
List<KeyDetails> acceptedKeysList = new ArrayList<>();
try {
KeyStoreCryptoManager keyStoreCryptoManager = new KeyStoreCryptoManager(getContext());
Js js = new Js(getContext(), null);
for (KeyDetails keyDetails : privateKeyDetailsList) {
String armoredPrivateKey = keyDetails.getValue();
String normalizedArmoredKey = js.crypto_key_normalize(armoredPrivateKey);
PgpKey pgpKey = js.crypto_key_read(normalizedArmoredKey);
V8Object v8Object = js.crypto_key_decrypt(pgpKey, passphrase);
if (pgpKey.isPrivate()) {
if (v8Object != null && v8Object.getBoolean(KEY_SUCCESS)) {
if (!keysDaoSource.isKeyExist(getContext(), pgpKey.getLongid())) {
Uri uri = keysDaoSource.addRow(getContext(),
KeysDao.generateKeysDao(keyStoreCryptoManager, keyDetails, pgpKey, passphrase));
PgpContact[] pgpContacts = pgpKey.getUserIds();
List<Pair<String, String>> pairs = new ArrayList<>();
if (pgpContacts != null) {
ContactsDaoSource contactsDaoSource = new ContactsDaoSource();
for (PgpContact pgpContact : pgpContacts) {
if (pgpContact != null) {
PgpKey publicKey = pgpKey.toPublic();
pgpContact.setPubkey(publicKey.armor());
if (js.str_is_email_valid(pgpContact.getEmail()) &&
contactsDaoSource.getPgpContact(getContext(), pgpContact.getEmail())
== null) {
new ContactsDaoSource().addRow(getContext(), pgpContact);Instead you should remove chunks and make them into methods, eg:
public void processAndSavePgpContacts(pgpContacts: PgpContact[]) {
ContactsDaoSource contactsDao = new ContactsDaoSource();
for (PgpContact pgpContact : pgpContacts) {
if (pgpContact != null) {
PgpKey publicKey = pgpKey.toPublic();
pgpContact.setPubkey(publicKey.armor());
String email = pgpContact.getEmail();
if (js.str_is_email_valid(email) && contactsDao.getPgpContact(getContext(), email) == null) {
new ContactsDaoSource().addRow(getContext(), pgpContact);
// todo-DenBond7 Need to resolve a situation with different public keys.
// For example we can have a situation when we have to different public
// keys with the same email
}
pairs.add(Pair.create(pgpKey.getLongid(), email));
}
}
}
// ...
if (pgpContacts != null) {
processAndSavePgpContacts(pgpContacts);
}- Save a value into a shorter variable if it repeats in a line and it would cause the line to not wrap, especially
ifstatements. This is bad:
if (js.str_is_email_valid(pgpContact.getEmail()) && contactsDao.getPgpContact(getContext(), pgpContact.getEmail())
== null) {
new ContactsDaoSource().addRow(getContext(), pgpContact);
}This is good:
String email = pgpContact.getEmail();
if (js.str_is_email_valid(email) && contactsDao.getPgpContact(getContext(), email) == null) {
new ContactsDaoSource().addRow(getContext(), pgpContact);
}The following are recommended - up to discussion - let me know what you think
- object properties related to count would start with lowercase n:
countOfLoadedMessages->nLoadedMessages,countOfNewMessages->nNewMessageswhile properties representing a number of something (order / position in a list) would be spelled out:messageNumberis correct- can start with
is,has,doesin a way that it makes sense in English:.isFolderHasNoSelectAttribute()->.doesFolderHaveNoSelectAttr() - except where negative name makes a lot of sense (should be rare), always use positive names:
o.doesFolderHaveNoSelectAttr()->!o.doesFolderHaveSelectAttr()ando.isKeyNotExistsInList()->!o.doesListContainKey()
- can start with
- Queue must always be named Q or q, and nothing else can be named Q or q.
activeSyncTaskBlockingQueue->activeSyncTaskBlockingQ Attachmentis a frequent word that can even show several times per line with no obvious short form. We could agree to always call itAttachment -> AttandAttachments -> Atts. It's not the most obvious for 3rd party developers, but if we agree on it and are consistent, it will shorten the code considerably.
Most of these rules result in shorter code. Shorter variable, class, property, method and object names mean that more code fits on a line (limit 120), which means that the line is less likely to be wrapped at the end. I find lines that wrap around a lot hard to read. Here is an example of how this can help:
// this spans half of a line
PropertiesHelper.generatePropertiesForDownloadGmailAttachments();
// updated by using code style above
PropsHelper.genPropsForDownloadGmailAttachments();
// but even better, which some shorter wording
PropsHelper.genGmailAttachmentDownloadProps();
// another example
messageDaoSource.updateMessageState(context,
generalMessageDetails.getEmail(), generalMessageDetails.getLabel(),
generalMessageDetails.getUid(), MessageState.SENDING);
// becomes
msgDao.updateMsgState(context, msgDetails.getEmail(), msgDetails.getLabel(),
msgDetails.getUid(), MsgState.SENDING);
// which is much more readable in my opinion