/CodeStyle

Primary LanguageShell

Pulselive Android Studio Coding Style

Codingstyle file can be found at TODO URL

To install the file, open Android Studio Settings and go to Editor > Code Style > Kotlin, then click the gear menu and choose Import Scheme....

All projects should follow the correct style guidelines.

Note: Following plugin is helpful in sorting methods in class : https://plugins.jetbrains.com/plugin/11410-android-sorter

Inspiration

This style-guide is somewhat of a mash-up between the existing Kotlin language style guides. The language guidance is drawn from:

Source files

All source files must be encoded as UTF-8.

Naming

On the whole, naming should follow Java standards, as Kotlin is a JVM-compatible language.

Packages

Package names are similar to Java: all lower-case, multiple words concatenated together, without hypens or underscores:

BAD:

com.pulselive.funky_widget

GOOD:

com.pulselive.funkywidget

Classes & Interfaces

Written in UpperCamelCase. For example :

	AndroidActivity, NetworkHelper, UserFragment, PerActivity

Any classes extending an Android framework component should always end with the component name. For example:

UserFragment, SignUpActivity, RateAppDialog, PushNotificationServer, NumberView

UpperCamelCase helps to seperate the words used to create the name, making it easier to read. Naming classes to end with the framework component makes it super clear as to what the class is used for. For example, if you're looking to make changes to the RegistrationDialog then this naming convention makes it really easy to locate that class.

Methods

Written in lowerCamelCase. For example setValue.

Fields

Generally, written in lowerCamelCase. Fields should not be named with Hungarian notation, as Hungarian notation is erroneously thought to be recommended by Google.

Example field names:

class MyClass {
  var publicField: Int = 0
  val person = Person()
  private var privateField: Int?
}

Constant values in the companion object should be written in uppercase, with an underscore separating words:

companion object {
  const val THE_ANSWER = 42
}

Variables & Parameters

Written in lowerCamelCase.

Single character values must be avoided, except for temporary looping variables.

Misc

In code, acronyms should be treated as words. For example:

BAD:

XMLHTTPRequest
URL: String? 
findPostByID

GOOD:

XmlHttpRequest
url: String
findPostById
Do Don't
setUserId setUserID
String uri String URI
int id int ID
parseHtml parseHTML
generateXmlFile generateXMLFile

Resource Files

When naming resource files you should be sure to name them using lowercase letters and underscores instead of spaces, for example:

activity_main, fragment_user, item_post

This convention again makes it really easy to locate the specific layout file that you're looking for. Within android studio, the layout package is sorted in alphabetical order meaning that activity, fragment and other layout types becomes grouped - so you know where to begin looking for a file. Other than this, beginning the file name with the component name makes it clear what component/class the layout file is being used for.

Drawable Files

Drawable resource files should be named using the ic_ prefix along with the size and color of the asset. For example, white accept icon sized at 24dp would be named:

ic_accept_24dp_white

And a black cancel icon sized at 48dp would be named:

ic_cancel_48dp_black

We use this naming convention so that a drawable file is recognisable by its name. If the colour and size are not stated in the name, then the developer needs to open the drawable file to find out this information. This saves us a little bit of time :)

Other drawable files should be named using the corresponding prefix, for example:

Type Prefix Example
Selector selector_ selector_button_cancel
Background bg_ bg_rounded_button
Circle circle_ circle_white
Progress progress_ progress_circle_purple
Divider divider_ divider_grey

This convention again helps to group similar items within Android Studio. It also makes it clear as to what the item is used for. For example, naming a resource button_cancel could mean anything! Is this a selector resource or a rounded button background? Correct naming helps to clear any ambiguity that may arise.

When creating selector state resources, they should be named using the corresponding suffix:

State Suffix Example
Normal _normal btn_accept_normal
Pressed _pressed btn_accept_pressed
Focused _focused btn_accept_focused
Disabled _disabled btn_accept_disabled
Selected _selected btn_accept_selected

Using clear prefixes such as the above helps to make it absolutely obvious as to what a selector state resource is used for. Prefixing resources with the colour or any other identifier again requires the developer to open the selector file to be educated in what the different selector state resources are.

Layout Files

When naming layout files, they should be named starting with the name of the Android Component that they have been created for. For example:

Component Class Name Layout Name
Activity MainActivity activity_main
Fragment MainFragment fragment_main
Dialog RateDialog dialog_rate
Widget UserProfileView view_user_profile
AdapterView Item N/A item_follower

Note: If you create a layout using the merge tag then the layout_ prefix should be used.

Not only does this approach makes it easy to find files in the directory hierarchy, but it really helps when needing to identify what corresponding class a layout file belongs to.

Menu Files

Menu files do not need to be prefixed with the menu_ prefix. This is because they are already in the menu package in the resources directory, so it is not a requirement.

Values Files

All resource file names should be plural, for example:

attrs.xml, strings.xml, styles.xml, colors.xml, dimens.xml

View Field Naming

When naming fields that reference views, the name of the view should be the last word in the name. For example:

View Name
TextView usernameView
Button acceptLoginView
ImageView profileAvatarView
RelativeLayout profileLayout

We name views in this way so that we can easily identify what the field corresponds to. For example, having a field named user is extremely ambiguous - giving it the name usernameView, userAvatarView or userProfieLayout helps to make it clear exactly what view the field corresponds with.

Declarations

Visibility Modifiers

Only include visibility modifiers if you need something other than the default of public.

BAD:

public val wideOpenProperty = 1
private val myOwnPrivateProperty = "private"

GOOD:*

val wideOpenProperty = 1
private val myOwnPrivateProperty = "private"

Access Level Modifiers

Access level modifiers should be explicitly defined for classes, methods and member variables.

Fields & Variables

Prefer single declaration per line.

GOOD:

username: String
twitterHandle: String

Classes

Exactly one class per source file, although inner classes are encouraged where scoping appropriate.

Data Type Objects

Prefer data classes for simple data holding objects.

BAD:

class Person(val name: String) {
  override fun toString() : String {
    return "Person(name=$name)"
  }
}

GOOD:

data class Person(val name: String)

Spacing

Indentation

Indentation is using spaces - never tabs.

Blocks

Indentation for blocks uses 4 spaces:

GOOD:

for (i in 0..9) {
    Log.i(TAG, "index=" + i);
}

Line Wraps

Lines should be no longer than 100 characters long. Indentation for line wraps should use 8 spaces.

GOOD:

val widget: CoolUiWidget =
        someIncrediblyLongExpression(that, reallyWouldNotFit, on, aSingle, line)

####Where to break The prime directive of line-wrapping is: prefer to break at a higher syntactic level. Also:

  • When a line is broken at a non-assignment operator the break comes before the symbol.
    • This also applies to the following “operator-like” symbols:
    • The dot separator (.).
    • The two colons of a member reference (::).
  • When a line is broken at an assignment operator the break comes after the symbol.
  • A method or constructor name stays attached to the open parenthesis (() that follows it.
  • A comma (,) stays attached to the token that precedes it.
  • A lambda arrow (->) stays attached to the argument list that precedes it.

####Functions When a function signature does not fit on a single line, break each parameter declaration onto its own line. Parameters defined in this format should use a single indent (+4). The closing parenthesis ()) and return type are placed on their own line with no additional indent.

GOOD:

fun <T> Iterable<T>.joinToString(
    separator: CharSequence = ", ",
    prefix: CharSequence = "",
    postfix: CharSequence = ""
): String {
    //
}

Getters & Setters

Unlike Java, direct access to fields in Kotlin is preferred.

If custom getters and setters are required, they should be declared following Kotlin conventions rather than as separate methods.

Brace Style

Only trailing closing-braces are awarded their own line. All others appear the same line as preceding code:

BAD:

class MyClass
{
  fun doSomething()
  {
    if (someTest)
    {
      // ...
    }
    else
    {
      // ...
    }
  }
}

GOOD:

class MyClass {
  fun doSomething() {
    if (someTest) {
      // ...
    } else {
      // ...
    }
  }
}

When Statements

Unlike switch statements in Java, when statements do not fall through. Separate cases using commas if they should be handled the same way. Always include the else case.

BAD:

when (anInput) {
  1 -> doSomethingForCaseOne()
  2 -> doSomethingForCaseOneOrTwo()
  3 -> doSomethingForCaseThree()
}

GOOD:

when (anInput) {
  1, 2 -> doSomethingForCaseOneOrTwo()
  3 -> doSomethingForCaseThree()
  else -> println("No case satisfied")
}

Annotations

Standard annotations should be used - in particular override. This should appear on the same line as the function declaration.

BAD:

fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState);
}

GOOD:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState);
}

Types

Constants vs. Variables

Constants are defined using the val keyword, and variables with the var keyword. Always use val instead of var if the value of the variable will not change.

Tip: A good technique is to define everything using val and only change it to var if the compiler complains!

XML Style Rules

Use self=-closing tags

When a View in an XML layout does not have any child views, self-closing tags should be used.

GOOD:

<ImageView
    android:id="@+id/image_user"
    android:layout_width="90dp"
    android:layout_height="90dp" />

BAD:

<ImageView
    android:id="@+id/image_user"
    android:layout_width="90dp"
    android:layout_height="90dp">
</ImageView>

ID naming

All IDs should be prefixed using the name of the element that they have been declared for.

Element Prefix
ImageView image_
Fragment fragment_
RelativeLayout layout_
Button button_
TextView text_
View view_

Strings

All string names should begin with a prefix for the part of the application that they are being referenced from. For example:

Screen String Resource Name
Registration Fragment “Register now” registration_register_now
Sign Up Activity “Cancel” sign_up_cancel
Rate App Dialog “No thanks” rate_app_no_thanks

If it’s not possible to name the referenced like the above, we can use the following rules:

Prefix Description
error_ Used for error messages
title_ Used for dialog titles
action_ Used for option menu actions
msg_ Used for generic message such as in a dialog
label_ Used for activity labels

Styles and themes

When defining both Styles & Themes, they should be named using UpperCamelCase. For example:

AppTheme.DarkBackground.NoActionBar
AppTheme.LightBackground.TransparentStatusBar

ProfileButtonStyle
TitleTextStyle

Tests style rules

Unit tests

Any Unit Test classes should be written to match the name of the class that the test are targeting, followed by the Test suffix. For example:

Class Test Class
DataManager DataManagerTest
UserProfilePresenter UserProfilePresenterTest
PreferencesHelper PreferencesHelperTest

All Test methods should be annotated with the @Test annotation, the methods should be named using the following template:

@Test
public void methodNamePreconditionExpectedResult() { }

So for example, if we want to check that the signUp() method with an invalid email address fails, the test would look like:

@Test
public void signUpWithInvalidEmailFails() { }

Order of methods in class

  • Variable (Properties, sort by alphabet)

  • Override Functions (Properties): Lifecycle methods first

  • Declared Functions:

- Public Functions (sort by alphabet)

- Private Functions (sort by alphabet)