Attitude
Your code should be easy redable & understandable for the other developers.Code should be written to minimize the time it would take for someone else to understand it.
Try to keep same code style everywhere over the code to prevent confuse of the reader.
* Most of below examples are relevant to Java, TypeScript, JavaScript languages
General
- Follow standard conventions.
- Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
- Boy scout rule. Leave the campground cleaner than you found it.
- Always find root cause. Always look for the root cause of a problem.
- Be consistent. If you do something a certain way, do all similar things in the same way.
Design rules
- Keep configurable data at high levels.
- Prefer polymorphism to if/else or switch/case.
- Prevent over-configurability.
- Use dependency injection.
- Follow Law of Demeter. A class should know only its direct dependencies.
- Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
- Avoid side-effects
- Prefer immutability (*.ts wrap types with
Readonly<>
) - Everything should be relevantly close to it’s usage...
Data structures
- Do one thing.
- Prefer fewer arguments.
- Avoid hybrids structures (half object and half data).
- Prefer Types over Interfaces for pure data structures.
- Base class should know nothing about their derivatives.
- Better to have many functions than to pass some code into a function to select a behavior.
- Avoid Circular Dependencies.
Code smells
- Rigidity. The software is difficult to change. A small change causes a cascade of subsequent changes.
- Fragility. The software breaks in many places due to a single change.
- Immobility. You cannot reuse parts of the code in other projects because of involved risks and high effort.
- Needless Complexity.
- Needless Repetition.
- Opacity. The code is hard to understand.
- Added multifunctional third-party library for just one use-case.
- Unnecessary type casts
(e.g. *.ts name: key as SomeName)
– use explicit typequards for it.
Naming
In Short
- Choose descriptive and unambiguous names.
- Use PascalCase for type names.
- Do not use
I
as a prefix for interface names. - Use camelCase for function names.
- Use camelCase for property names and local variables.
- Do not use
_
as a prefix for private properties. - Use whole words in names when possible.
- Use explanatory constants (avoid magic numbers).
Pack information into your names (Think of names as a tiny comment)
-
Make meaningful distinction – try to pick self-commentary name.
-
Avoid generic names (or know when to use them).
But don't forget that any extra info you squeeze into a name will be seen every time the variable is seen. -
Prefer concrete names instead of abstract names (give the names that directly describe what the method will do). Attach an extra info to a name by using suffix especially in the places where a bug can easily sneak if someone mistakes that the variable is:
elapsed_ms
,members[mi]
,html_utf8
,plained_password
,data_urlenc
,model_onDataReceived
, etc. -
Find more "Colorful" words:
send -> deliver, dispatch, announce, distribute, route, sendBets; find -> search, extract, locale, recover, findLetter; start -> create, launch, begin, open, startRound; make -> create, setUp, build, generate, compose, add.
-
If you're going to use a generic name like
tmp
, it orretval
, have a good reason for doing so. -
Use longer names for larger scope's (shorter names are better for variables that span only few lines).
-
The clearest way to name a limit is to add
max_
ormin_
in front of the thing being limited:MAX_ITEM_IN_CARD
,minRange
,maxRange
. -
Prefer
first/last
andmin/max
instead ofstart/stop
for inclusive ranges (where the range should include both end points). -
The typical convention for naming inclusive/exclusive ranges (where the range should include the begin point and exclude the end point) is
begin/end
.
For example: All events that happened on October 20, it's easier to write:showEventsInRange("OCT 20 12:00am", "OCT 21 12:00am");
than it's to write:
showEventsInRange("OCT 20 12:00am", "OCT 21 11:59:59:9999am");
-
Use the
compute/calculate
prefixes in 'get' methods that should iterate over past data before returning some value (cause calling such method may be very expensive if there a lot of data, but unsuspecting programmer might call it carelessly).
Abbreviations
Avoid them as a general rule. For example, calculateOptimalValue()
is better method name than calcOptVal()
.
Being clear is more important than minimizing keystrokes. And if you
don't abbreviate, developers won't have to remember whether you
shortened a word like qualified
to qual
or qlfd
.
However, the are few standardized abbreviations:
acc
for accessibility, asButtonAccImpl
;auto
for automatic, as inautoLayout
eval
for evaluate, as inEvalBindingResponder
impl
for implementation, as inButtonAccImpl
info
for information, as inGridRowInfo
num
for number of, as innumChildren
min
for minimum, as inminWidth
max
for maximum, as inmaxHeight
nav
for navigation, asNavBar
regexp
for regular expression, as inRegExpValidator
util
for utility, asStringUtil
enum
for enumerator, asGameType
If you're considering using an abbreviation that isn't listed here, please search the source code to determine whether it is already in use. If you don't find it, think twice about whether abbreviating is really appropriate.
Whatever u can spell out “horizontal” and “vertical” in most places, such
as horizontalScroll
and verticalScroll
but abbreviate them to H
and V
in the very-commonly-used container names HBox
and VBox
.
Acronyms
Various acronyms are common, such as CSS
, HLOC
, IME
, RX
, MXML
, RPC
, RSL
, UI
, UID
, URL
, WSDL
, XML
, JSON
.
An acronym is always all-uppercase or all-lowercase (e.g., URL
or url
, but never Url
).
The only time that all-lowercase is used is when the acronym is used by
itself as an identifier, or at the beginning of an identifier, and the
identifier should start with a lowercase letter.
Examples of identifiers with acronyms are CSSStyleDeclaration
, IUID
, ui
, id
, itemID
, url
, pictureURL.Follow
the acronym-casing rules even in the rare case that two acronyms
must be adjacent. An example (which isn't actually in use) would be
something like loadCSSURL()
. But try to avoid such names. Better will be loadCSSfromURL()
or loadExternalCSS()
.
Type-specifying names
If you want to incorporate the type into the name, make it the last “word”.
Don't use the old conventions of concatenating abbreviated type suffixes such as _btn to indicate type.
For example, name a border Shape border, borderSkin
, or borderShape
, but not border_ui.
Often, the best name for an object is simply the same as its type, with different casing:
Button button = new Button();
// or more specific:
Button quoteButton = new Button();
Package names
Start them with a lowercase letter and use underscores for subsequent words: controls
, list_classes
.
The package that contains a lot of similar things should have name in plural form: controls
, filters
, commands
, events
, managers
, resources
, skins
, states
, styles
, utils
, validators
.
It is common to use a gerund for the name of a package which implements a concept: binding
, logging
, messaging
, printing
, mapping.Otherwise
, they are generally "concept nouns": core
, graphics
, api
.
Namespace names
Start them with a lowercase letter and use underscores between words: fx_internal
, obxect_proxy
.
Interface names
Just give a proper general name, that corresponds to api e.g. List
, Set
, Repository
There was old convention to start them with I
and use intercaps (camelCase) for subsequent words: IList
, IFocusManager
.
But, developer works with an object and should not care whether it's an interface or actual implementation.
There is also wide popular to add Impl
to the end of the implementation, but better to give your implementation more specific name instead e.g. ArrayList
, HashSet
, PropertiesRepository
Class names
Start them with uppercase and use camelCase: Button
, FocusManager
, UIComponent
, FooBarEvent
, FooBarError
, FooBarInstance
, FooBarValidator
, FooBarBorder
, FooBarSkin
, FooBarIcon
, FooBarUtil
, etc.
There is also holly war about names, that end on er
and or
.
I'm sure, that's is more than fine to use such in natural entities like Error
, Border
, Actor
Constant names
Use all uppercase letters and use underscores between words: DEFAULT_WIDTH
, OFF
.
The words in the identifier must match the words in the constant value if it is a String
:
public static final String FOO_BAR = "fooBar";
Instance names
Do not use "_"
as a prefix for private properties.
Getter/Setter & Argument names
Give the storage variable for the getter/setter getFoo/setFoo
the name foo
.
Type declarations
Use the narrowest type that is appropriate.
For example, a loop index should be a int, not a long*. e.g mouseEventHandler
should declare its argument type as MouseEvent
, not Event
.
// Do this:
public String setLabel(String value) {...}
// or this
public String setLabel(String label) {...}
// Not this:
public String setLabel(String labelValue) {...}
// or this:
public String setLabel(String val) {...}
Use event
(not e
, evt
, or eventObj
) for the argument of every event handler:
public void onApplicationEvent(BalanceUpdateEvent event) {...}
Event handler names
Event handlers should be named by concatenating "Handler" to the type of the event: mouseEventHandler()
.
If the handler is for events dispatched by a subcomponent (i.e., not this), prefix the handler with the subcomponent name and underscore: textInput_focusInHandler()
, model_betConfirmHandler()
Anyway nobody likes to write extra code, so on
prefix works properly in any project onMouseEvent()
.
* Whichever style you choose, be consistent so that it does not become an overhead for your team to process multiple styles in related pieces of code.
Statements
Despite of some advantages of Allman indentation style Egyptian braces style is used more widely in java world and especially in script languages like JavaScript and TypeScript.
- The
{
(opening brace) should be at the end of the line that begins the compound statement; - The
}
closing brace should begin a line and be indented to the beginning of the compound statement.
* "Compound statements" - are statements that contain lists of statements enclosed in braces { statements }
Import statements
Avoid using .*
(group imports) if you don't use whole group in your class.
if
, if-else
, if-else-if-else
, for
, while
, do
statements
Braces should be used around all statements, even single statements, when those are part of a control structure, such as an if
or for
statement.
This makes it easier to add statements without accidentally introducing bugs to forgetting to add braces.
Follow the if
, if else
, for
, while
, switch
statements with a single space ' '
before the left parenthesis:
// Do this:
if (a < b) {...}
// And this:
for (int i = 0; i < n; i++) {...}
// Not these:
if(a<b) {...}
if(a < b) {...}
if( a < b ) {...}
Try to not use more than 2 nested if
statements inside each other:
// Do this:
if (!condition1) {
return false;
}
...
if (!condition2) {
return false;
}
...
if (!condition3) {
return false;
}
...
return true;
// Not this:
if (condition1) {
...
if (condition2) {
...
if (condition3) {
...
return true
}
}
}
return false;
switch
statements
Every switch
statement should include a default
case.
The break
in the default
case is redundant, but it prevents a fall-through error if later another case is added.
switch (condition) {
case A: // falls through B
case B:
statements;
/* falls through C*/
case C:
statements;
break;
default:
statements;
break;
}
White space
Blank Lines
Blank lines improve readability by setting off sections of code that are logically related.
Two blank lines should always be used in the following circumstances:
- Between sections of a source file
- Between class and interface definitions
One blank line should always be used in the following circumstances:
-
Between methods
-
Between the local variables in a method and its first statement
-
Before a block or single-line comment
Javaif (condition) { /* Handle the condition. */ ... }
-
Between logical sections inside a method to improve readability
Blank Spaces
-
A keyword followed by a parenthesis should be separated by a space:
Javawhile (true) {...}
-
A blank space should not be used between a method name and its openings parenthesis, but should appear after commas in argument lists:
JavadoSomething(String foo, String bar) {...}
-
The expressions in a for statement should be separated by blank spaces:
Javafor (expr1; expr2; expr3) {...}
-
All binary operators except . should be separated from their operands by spaces:
Javaa += c + d; a = (a + b) / (c * d); while (d++ = s++) { n++; }
Indentation
Block indentation: +2 spaces
Each time a new block or block-like construct is opened, the indent increases by two spaces.
When the block ends, the indent returns to the previous indent level.
The indent level applies to both code and comments throughout the block.
* All code samples here formatted in this way.
Indent continuation lines at least +4 spaces
When line-wrapping, each line after the first (each continuation line) is indented at least +4 from the original line.
In general, two continuation lines use the same indentation level if and only if they begin with syntactically parallel elements.
Do things in more natural way!
Comparison
Write comparisons in the order that they read most naturally:
// Do this:
if (n == 3) {...} // "if n is 3"
// Not this:
if (3 == n) {...} // "if 3 is n"
++
and --
operators
Prefer postfix form in ++
and --
operators:
// Do this:
for (int i = 0; i < n; i++)
// Not this:
for (int i = 0; i < n; ++i)
Ternary operator
Use a ternary operator in place of a simple if/else
statement, especially for null
checks:
// Do this:
return (item != null) ? item.label : defaultLabel;
// Not this:
if (item == null) {
return defaultLabel;
}
return item.label;
// But Don't use nested ternary operators!
// Don't do this:
return a < b ? -1 : (a > b ? 1 : 0);
// Do this:
if (a < b) {
return -1;
} else if (a > b)
return 1;
}
return 0;
If an expression containing a binary operator appears before the ? in the ternary ?: operator, it should be parenthesized:
// Do this:
return (item != null) ? item.label : defaultLabel;
// And this:
return flag ? "foo" : "bar";
// Not this:
return item != null ? item.label : defaultLabel;
Coercion
Don't compare a Boolean
value to true or false; it already is one or the other:
// Do this:
if (flag) {...}
// Not this:
if (flag == true) {...}
// And this:
if (a && b) {...}
// Not this:
if ((a && b) != false) {...}
Miscelanious
Initialization
Try to initialize local variables where they’re declared. The only reason not to initialize a variable where it’s declared is if the initial value depends on some computation occurring first.
// Do this:
String foo = "Bar";
// Not this:
String foo;
foo = "Bar";
One statement per line
Each statement is followed by a line break.
argv++; argc--; // Avoid this!
see Also
** Many of concepts above were applied from “The Clean Code” — Robert C. Martin
No comments:
Post a Comment