Índice:
- 1. Nomenclatura
- 2. Funções/Métodos
- 3. Classes e Entidades: Programação Orientada a Objetos - SOLID
- 4. Bibliografia e recomendações de leitura
Obs.: Todos os exemplos está na linguagem Java
1. Nomenclatura ↑
Use nomes relevantes, significativos e de fáceis entendimento para atribuir à classes, funções, variáveis, etc.
Obs.: Se um nome exigir um comentário, não há clareza de seu propósito. Refatore para um nome mais significativo.
👎 Bad Code | 👍 Code Clean | Rules |
---|---|---|
int dsc | int daysSinceCreation | Não use nomes inteiros com abreviações |
String string2 | String legalDocument | Não use nomes genéricos demais |
User[] userList | User[] users | Seja coeso (Array != List) |
List theUserListWithAllUsersIncluded | List allUsers | Seja objetivo (evite nomes enormes) |
boolean valid | boolean isValid | Use éAlgo (isSomething) |
boolean value() | boolean hasValue() | Use hasAlgo (hasSomething) |
1.1. Use nomes significativos em seus contextos próprios: ↑
Não recomendado:
String addressNumber
String addressStreet
String addressCity
Recomendado:
class Address {
...
String number;
String street;
String city;
}
1.2. Padronize os nomes, não misture conceitos: ↑
Não recomendado:
void loadData()
void fetchDataFiltered()
void getAllData()
Recomendado:
void getData()
void getFilteredData()
void getAllData()
- O mesmo conceito de "get" foi utilizado para "load” e “fetch”.
1.3. Prefira usar notações para explicar seu código: ↑
Não recomendado:
for (int i=0; i <= 7; i++) {
if ( i == 6 ) {
System.out.println(w[i]);
}
}
Recomendado:
final int NUMBER_DAYS_WEEK = 7;
final int SUNDAY = 6;
... {
for (int i=0; i <= NUMBER_DAYS_WEEK; i++) {
if ( i == SUNDAY ) {
System.out.println(daysOfTheWeek[i]);
}
}
- É adicionado mais linhas, entretanto, perceba que o código fica mais legível.
1.4. Use verbos para nomes de funções e substantivos para nome de classes e variáveis ↑
Não recomendado:
public class Calculate {
public void addition() {
...
}
}
Recomendado:
public class Calculator {
public void sum() {
...
}
}
1.5. Priorize nomes que expressem sentido positivo ↑
Não recomendado:
void convert() throws Exception {
if (shoudNotConvert()) {
throw new CantConvertException();
}
...
}
Recomendado:
void convert() throws Exception {
if (canConvert()) {
...
} else {
throw new CantConvertException();
}
}
- Afirmações negativas são um pouco mais difíceis para entender do que a afirmativas.
2. Funções/Métodos ↑
É recomendável que uma função/método seja curto. Qualquer método com mais de dez linhas, é interessante questionar se precisa refatorar para melhor compreensão deste.
2.1. Extração: Quebre uma método grande em métodos menores ↑
- Desta maneira, aumenta a compreensão e leitura.
Não recomendado:
public class Product {
// ...
public double calculateTotal() {
double total = product.quantity * product.price;
if (total > 200) {
total *= 0.85;
}
return total;
}
Recomendado:
public class Product {
// ...
public double calculateTotal() {
double total = calculatePriceByQuantity();
total = applyDiscounts(total);
return total;
}
private double calculatePriceByQuantity() {
return product.quantity * product.price;
}
private double applyDiscounts(double total) {
return (total > 200) ? (total * 0.85) : total;
}
2.1.2 Extração: Decomponha as condições ↑
Não recomendado:
boolean hasValidLegalDocument(String doc) {
if (11 === doc.length || 14 == doc.length) {
...
}
Recomendado:
final int CPF_SIZE = 11;
final int CNPJ_SIZE = 14;
boolean hasValidLegalDocument(String doc) {
if (hasLegalDocProperSize(doc.length)) {
...
}
boolean hasLegalDocProperSize(final int length) {
return (CPF_SIZE == length || CNPJ_SIZE == length);
}
2.2 Evite muitos parâmetros, preserve os objetos ↑
Não recomendado:
PagedList<User> list() {
...
return page(form.start, form.pageSize, form.search, form.field);
}
PagedList<User> page(int start, int pageSize, String search, String field) { ... }
Recomendado:
PagedList<User> list() {
...
return page(form);
}
PagedList<User> page(SearchForm form) { ... }
2.3 Evite - quando possível - retornar nulo ↑
Não recomendado:
public List<User> getActiveUsers() {
return repository.getActiveUsers();
}
Recomendado:
public List<User> getActiveUsers() {
List<User> users = repository.getActiveUsers();
return null == users ? Collections.<User>emptyList() : users;
}
- Uma excelente alternativa, seria utilizando o tipo Nullable, dependendo da linguagem.
2.4 Evite duplicação de códigos ↑
Não recomendado:
public void save() throws Exception {
if (null == this.name) {
throw new Exception("Faltando preencher o campo: Nome");
}
if (null == this.description) {
throw new Exception("Faltando preencher o campo: Descrição");
}
repository.save(this);
}
public void update() throws Exception {
if (null == this.name) {
throw new Exception("Faltando preencher o campo: Nome");
}
if (null == this.description) {
throw new Exception("Faltando preencher o campo: Descrição");
}
repository.update(this);
}
Recomendado:
public void save() throws Exception {
if (hasPropertiesChecked())
repository.save(this);
}
public void update() throws Exception {
if (hasPropertiesChecked())
repository.update(this);
}
private boolean hasPropertiesChecked() throws Exception {
String final defaultMessage = "Faltando preencher o campo: %s";
if (null == this.name) {
throw new Exception(String.formar(defaultMessage, "Nome");
}
if (null == this.description) {
throw new Exception(String.formar(defaultMessage, "Descrição");
}
return true;
}
2.5. Parametrize funções/métodos similares e evite repetições ↑
Não recomendado:
double tenPercentGain() { ... }
double ninePercentGain() { ... }
double twoPercentGain() { ... }
Recomendado:
double calculePercentGain(double percent) { ... }
3. Classes e Entidades: Programação Orientada a Objetos - SOLID ↑
Tem-se os 5 princípios do SOLID, como boas práticas para Programação Orientada a Objetos (P.O.O.).
3.1. 'S' (SRP) - Princípio da Responsabilidade Única ↑
Uma classe deve ter somente uma razão para mudar.
Não recomendado:
public class Establishment {
public double calculateDiscount(Sale sale) { ... }
...
}
public class Sale {
...
}
Recomendado:
public class Establishment {
public double getSaleDiscount() {
return this.getSale().calculateDiscount();
}
}
public class Sale {
public double calculateDiscount() { ... }
...
}
Não recomendado:
class Person {
@Override
toString() { ... }
Person save(Person person) { ... }
}
Recomendado:
class Person {
@Override
String toString() { ... }
Person save(Person person) { ... }
}
class PersonDB {
Person save(Person person) { ... }
}
Evite:
public void sendEmail(to, from, text) {
...
}
Use:
public class Email {
String to;
String from;
String text;
public void send() {
...
}
}
3.2. 'O' (OCP) - Princípio Aberto-Fechado ↑
- Entidades de software (classes, módulos, funções, etc.) devem ser abertas para extensão, mas fechadas para modificação.
- Use Classes Abstratas e polimofismo para resolver estes problemas!
Não recomendado:
class File { ... }
class WordFile {
public void generateWord() { ... }
}
class PdfFile {
public void generatePdf() { ... }
}
class FileController {
public void generateFiles(IList<File> fileList) {
fileList.forEach(file -> {
if (file instanceof WordFile) {
((WordFile) file).generateWord();
} else if (file instanceof PdfFile) {
((PdfFile) file).generatePdf();
}
// Cada novo arquivo, será adicionada mais uma condição
});
}
}
Recomendado:
abstract class File {
public void generate();
}
class WordFile extends File {
@Override
public void generate() { ... }
}
class PdfFile extends File {
@Override
public void generate() { ... }
}
class TextFile extends File {
@Override
public void generate() { ... }
}
class FileController {
public void generateFiles(IList<File> fileList) {
fileList.forEach(file -> file.generate());
}
}
3.3. 'L' (LSP) - Princípio de Substituição de Liskov ↑
Tipos derivados devem ser completamente substituíveis por seus tipos de base.
Não recomendado:
class Rectangle {
private int width;
private int height;
// getters e setters mothods...
}
class Square extends Rectangle {
@Override
public void setWidth(int width) {
super.width(width);
super.height(width);
}
@Override
public void setWeight(int length) {
super.width(length);
super.height(length);
}
}
Recomendado:
class Rectangle {
private int width;
private int height;
// getters, setters mothods...
}
class Square {
private int side;
// get, set mothods...
}
-
- Uma classe não pode utilizar herança pelo simples fato de ter algo em comum.
-
- Um retângulo é um quadrado, porém não o inverso. Em caso de polimorfismo, o exemplo acima - não recomendado - surtirá efeitos colaterais.
3.4. 'I' (ISP) - Princípio da segregação de interfaces ↑
- Uma interface deve ser quebrada em interfaces menores, evitando implementação forçada de todos os seus métodos por causa do contrato.
Não recomendado:
interface ITelephone {
void call();
void turnOnOff();
void takePicture() throws NotImplementedException;
}
class Phone implements ITelephone {
void call() { ... }
void turnOnOff() { ... }
void takePicture() throws NotImplementedException
{ throw new NotImplementedException(); }
}
class CellPhone implements ITelephone {
void call() { ... }
void turnOnOff() { ... }
void takePicture() { ... }
}
Recomendado:
interface ITelephone {
void call();
void turnOnOff();
}
interface ICellPhone extends ITelephone {
void takePicture();
}
class Telephone implements ITelephone {
void call() { ... }
void turnOnOff() { ... }
}
class CellPhone implements ICellPhone {
void call() { ... }
void turnOnOff() { ... }
void takePicture() { ... }
}
3.5. 'D' (DIP) - Princípio da Inversão de Dependência ↑
Não recomendado:
class Service {
FirstSender firstSender;
SecondSender secondSener;
public void send (Message message) {
if (message.type == FIRST) {
new FirstSender().send(message);
}
else (message.type == SECOND) {
new SecondSender().send(message);
}
...
}
}
Recomendado:
interface ISender {
send(Message message);
}
class SenderFactory {
ISender sender = null;
public static ISender create (Type type) {
if (type == FIRST) {
sender = new FirstSender();
}
else (type == SECOND) {
sender = new SecondSender();
}
...
return sender;
}
}
class Service {
void send (Message message) {
SenderFactory.create(message.type).send(message);
}
}
- Utilizar Injeção de Dependência (se possível), também ajuda no desacoplamento dessas classes.
3.6. Padrão BUILD para construção de uma classe ↑
Não recomendado:
public class Person {
private String firstName;
private String middleName;
private String lastName;
private int age;
public Person(String firstName, String middleName, String lastName, int age) {
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.age = age;
}
public Person(String firstName, String lastName, int age) {
this(firstName, null, lastName, age);
}
public Person(String firstName, int age) {
this(firstName, null, age);
}
// getters e setters...
}
Recomendado:
public class Person {
private String firstName;
private String middleName;
private String lastName;
private int age;
public static class Builder {
// Obrigatórios
private String firstName;
private int age;
// Opcionais
private String middleName;
private String lastName;
// Obrigatórios
public Builder(String firstName, int age){
this.firstName = firstName;
this.age = age;
}
// Opcionais
public Builder middleName(String middleName) {
this.middleName = middleName;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Person build() {
return new Person(this);
}
}
private Person(Builder builder) {
firstName = builder.firstName;
age = builder.age;
middleName = builder.middleName;
lastName = builder.lastName;
}
}
...
Person person = new Person.Builder("Gustavo", 23)
.middleName("Melo")
.lastName("Silva")
.build();
- Padrão válido apenas quando existem atributos opcionais.
4. Bibliografia e recomendações de leitura ↑
- Clean Code: A Handbook of Agile Software Craftsmanship - Robert C. Martin
- Design Principles and Design Patterns - Robert C. Martin
- Code Patterns - Acessado em: 07/09/2019
- Clean code 101 — Meaningful names and functions - Acessado em: 07/09/2019
- SOLID Principles: Explanation and examples - Acessado em: 07/09/2019
- Clean, high quality code: a guide on how to become a better programmer - Acessado em: 07/09/2019