Download presentation
Presentation is loading. Please wait.
1
Object Calisthenics Gabriel Heming
2
Gabriel Heming
3
ORIGEM Cal • is • then • ics - /ˌkaləsˈTHeniks/ Origem grega;
Exercícios no contexto de ginástica.
4
ORIGEM The ThoughtWorks Anthology - Jeff Bay; Conjunto de exercícios;
Nove regras (não universais);
5
MOTIVAÇÃO Manutenibilidade; Legibilidade; Testabilidade; Compreensão.
6
RESUMINDO
7
Only one level of indentation per method;
RULE #1: Only one level of indentation per method;
8
1 2 3 public String Board() { StringBuilder buf = new StringBuilder();
if (this.Data.Length >= 3) for (int i = 0; i < this.Data.Length; i++) for (int j = 0; j < this.Data[i].Length; j++) buf.Append(this.Data[i][j]); } buf.Append("\n"); return buf.ToString(); Validação 1 2 3 8
9
StringBuilder buf = new StringBuilder(); if (this.Data.Length < 3)
public String Board() { StringBuilder buf = new StringBuilder(); if (this.Data.Length < 3) return buf.ToString(); } for (int i = 0; i < this.Data.Length; i++) for (int j = 0; j < this.Data[i].Length; j++) buf.Append(this.Data[i][j]); buf.Append("\n"); Early return 9
10
EXTRACT METHOD Martin Fowler
11
StringBuilder buf = new StringBuilder(); if (this.Data.Length < 3)
public String Board() { StringBuilder buf = new StringBuilder(); if (this.Data.Length < 3) return buf.ToString(); } for (int i = 0; i < this.Data.Length; i++) buf.Append(this.CollectColumns(this.Data[i])); buf.Append("\n"); public String CollectColumns(string[] data) foreach (string row in data) buf.Append(row); 11
12
if (this.Data.Length < 3) return buf.ToString();
public String Board() { if (this.Data.Length < 3) return buf.ToString(); return this.CollectRows(this.Data); } public String CollectRows(string[][] data) StringBuilder buf = new StringBuilder(); foreach (string[] row in data) buf.Append(this.CollectColumns(row)); buf.Append("\n"); return buf.ToString(); public String CollectColumns(string[] data) foreach (string row in data) buf.Append(row); 12
13
Muito simples?
14
public static void SitefPaymentsAbort(Sales sales) {
foreach (Payment payment in sales.Payments) if (payment.objSitefProvider != null && !string.IsNullOrEmpty(payment.objSitefProvider.receiptNumber)) payment.objSitefProvider.Abort(payment.objSitefProvider.receiptNumber, payment.objSitefProvider.DateTime); } foreach (TenderLineItem tenderlineitem in ((RetailTransaction)sales.transaction).TenderLines) if (tenderlineitem.LineId == payment.tenderLineItem.LineId) if (tenderlineitem is GiftCertificateTenderLineItem) if (sales.application.TransactionServices.CheckConnection()) bool released = true; string comment = ""; sales.application.TransactionServices.GiftCardRelease(ref released, ref comment, ((GiftCertificateTenderLineItem)tenderlineitem).SerialNumber); 14
15
public static void SitefPaymentsAbort(Sales sales) {
foreach (Payment payment in sales.Payments) SalesOrder.SitefPaymentAbort(sales , payment); } private static void SitefPaymentAbort(Sales sales, Payment payment) if (payment.objSitefProvider != null && !string.IsNullOrEmpty(payment.objSitefProvider.receiptNumber)) payment.objSitefProvider.Abort(payment.objSitefProvider.receiptNumber, payment.objSitefProvider.DateTime); foreach (TenderLineItem tenderlineitem in ((RetailTransaction)sales.transaction).TenderLines) if (tenderlineitem.LineId == payment.tenderLineItem.LineId) if (tenderlineitem is GiftCertificateTenderLineItem) if (sales.application.TransactionServices.CheckConnection()) bool released = true; string comment = ""; sales.application.TransactionServices.GiftCardRelease(ref released, ref comment, ((GiftCertificateTenderLineItem)tenderlineitem).SerialNumber); 15
16
private static void SitefPaymentAbort(Sales sales, Payment payment) {
/** código omitido **/ foreach (TenderLineItem tenderlineitem in ((RetailTransaction)sales.transaction).TenderLines) if (tenderlineitem.LineId == payment.tenderLineItem.LineId) if (tenderlineitem is GiftCertificateTenderLineItem) if (sales.application.TransactionServices.CheckConnection()) bool released = true; string comment = ""; sales.application.TransactionServices.GiftCardRelease(ref released, ref comment, ((GiftCertificateTenderLineItem)tenderlineitem).SerialNumber); } Validações 16
17
private static void SitefPaymentAbort(Sales sales, Payment payment) {
/** código omitido **/ IEnumerable<TenderLineItem> tenderLineItemList = ((RetailTransaction)sales.transaction).TenderLines.Where( tenderLineItem => tenderLineItem.LineId == payment.tenderLineItem.LineId && tenderLineItem is GiftCertificateTenderLineItem ); foreach (TenderLineItem tenderlineitem in tenderLineItemList) if (sales.application.TransactionServices.CheckConnection()) bool released = true; string comment = ""; sales.application.TransactionServices.GiftCardRelease(ref released, ref comment, ((GiftCertificateTenderLineItem)tenderlineitem).SerialNumber); } 17
18
private static void SitefPaymentAbort(Sales sales, Payment payment) {
/** código omitido **/ IEnumerable<TenderLineItem> tenderLineItemList = ((RetailTransaction)sales.transaction).TenderLines.Where( tenderLineItem => tenderLineItem.LineId == payment.tenderLineItem.LineId && tenderLineItem is GiftCertificateTenderLineItem ); foreach (TenderLineItem tenderlineitem in tenderLineItemList) SalesOrder.GiftCardRelease(sales, tenderLineItem); } private static void GiftCardRelease(SalesOrder sales, TenderLineItem tenderlineitem) if (sales.application.TransactionServices.CheckConnection()) bool released = true; string comment = ""; sales.application.TransactionServices.GiftCardRelease(ref released, ref comment, ((GiftCertificateTenderLineItem)tenderlineitem).SerialNumber); 18
19
public static void SitefPaymentsAbort(Sales sales)
{ foreach (Payment payment in sales.Payments) SalesOrder.SitefPaymentAbort(sales , payment); } private static void SitefPaymentAbort(Sales sales, Payment payment) if (payment.objSitefProvider != null && !string.IsNullOrEmpty(payment.objSitefProvider.receiptNumber)) payment.objSitefProvider.Abort(payment.objSitefProvider.receiptNumber, payment.objSitefProvider.DataHoraTransacao); IEnumerable<TenderLineItem> tenderLineItemList = ((RetailTransaction)sales.transaction).TenderLines.Where( tenderLineItem => tenderLineItem.LineId == payment.tenderLineItem.LineId && tenderLineItem is GiftCertificateTenderLineItem ); foreach (TenderLineItem tenderlineitem in tenderLineItemList) SalesOrder.GiftCardRelease(sales, tenderLineItem); private static void GiftCardRelease(SalesOrder sales, TenderLineItem tenderlineitem) if (sales.application.TransactionServices.CheckConnection()) bool released = true; string comment = ""; sales.application.TransactionServices.GiftCardRelease(ref released, ref comment, ((GiftCertificateTenderLineItem)tenderlineitem).SerialNumber); 19
20
BENEFÍCIOS S.R.P. (Single Responsibility Principle);
Redução lógica por métodos; Legibilidade; Reusabilidade.
21
RULE #2: Don’t use the else keyword
22
Por que?
23
COMPLEXIDADE CICLOMÁTICA
24
Defensive Programming
25
public Entity Create(Entity entity) { if (entity.IsValid())
Repository repository = this.GetRepository(entity); if (!repository.Exists(entity)) return repository.Save(entity); } else throw new ArgumentException("The entity already exists"); throw new ArgumentException("Invalid entity"); 25
26
public Entity Create(Entity entity) { if (!entity.IsValid())
throw new ArgumentException("Invalid entity"); } Repository repository = this.GetRepository(entity); if (!repository.Exists(entity)) return repository.Save(entity); else throw new ArgumentException("The entity already exists"); 26
27
public Entity Create(Entity entity) { if (!entity.IsValid())
throw new ArgumentException("Invalid entity"); } Repository repository = this.GetRepository(entity); if (repository.Exists(entity)) throw new ArgumentException("The entity already exists"); return repository.Save(entity); 27
28
OUTRAS ABORDAGENS Chain of Responsibility Pattern; State Pattern.
29
BENEFÍCIOS Evita duplicidade; Aumenta a legibilidade;
Reduz a complexidade ciclomática.
30
RULE #3: Wrap all primitives and STRINGS
31
Primitive Obsession anti-pattern
32
SOMENTE TIPOS COM COMPORTAMENTO
33
87,43 Sub 0?? 77,43 ????????? Add -10?? class BankAccount
{ private double amount; public void Add(double money) this.amount += money; } public void Sub(double money) this.amount -= money; public double Total() return this.amount; BankAccount account = new BankAccount(); account->Add(10); account->Add(12.25); account->Add(27.50); account->Add(55); account->Sub(17.32); account->Total(); 87,43 account->Add(-10); account->Sub(0); account->Total(); Sub 0?? 77,43 ????????? Add -10?? 33
34
Lógica duplicada class BankAccount { private double amount;
public void Add(double money) if (money <= 0) throw new ArgumentException("money não pode ser igual ou menor que zero"); } this.amount += money; public void Sub(double money) this.amount -= money; public double Total() return this.amount; Lógica duplicada 34
35
private double amount; public Money(double amount) if (money <= 0)
class Money { private double amount; public Money(double amount) if (money <= 0) throw new ArgumentException("money não pode ser igual ou menor que zero"); } this.amount = amount; public double GetAmount() return this.amount; class BankAccount { private double amount; public void Add(Money money) this.amount += money->GetAmount(); } public void Sub(Money money) this.amount -= money->GetAmount(); public double Total() return this.amount; BankAccount account = new BanckAccount(); account->Add(new Money(10)); account->Add(new Money(-10)); // throw ArgumentException 35
36
BENEFÍCIOS Evita duplicidade; Encapsulamento; Domain Driven Design.
37
First class collections
RULE #4: First class collections
38
public List<Address> AddressList { get; internal set; } }
public class Person { public List<Address> AddressList { get; internal set; } } public class Address public Type Type { get ; set; } public enum Type Residential, Commercial List<Address> residentialAddressList = person.AddressList.Where( address => address.Type == Type.Residential ).ToList() List<Address> residentialAddressList = person.AddressList.Where( address => address.Type == Type.Commercial ).ToList() 38
39
E SE PRECISAR FILTRAR EM DIFERENTES LUGARES?
40
Responsabilidades demais
class Person { public List<Address> AddressList { get; internal set; } public List<Address> GetResidentialAddressList() return this.AddressList.Where( address => address.Type == Type.Residential).ToList(); } public List<Address> GetCommercialAddressList() address => address.Type == Type.Commercial).ToList(); Responsabilidades demais List<Address> residentialAddressList = person.GetResidentialAddressList(); List<Address> commercialAddressList = person.GetCommercialAddressList(); 40
41
CADA UM COM SUA RESPONSABILIDADE
42
public class AddressCollection {
public List<Address> GetResidentialAddressList() return this.AddressList.Where( address => address.Type == Type.Residential).ToList(); } public List<Address> GetCommercialAddressList() address => address.Type == Type.Commercial).ToList(); public class Person public AddressCollection AddressCollection { get; internal set; } List<Address> residentialAddressList = person.AddressCollection.GetResidentialAddressList(); List<Address> commercialAddressList = person.AddressCollection.GetCommercialAddressList(); 42
43
BENEFÍCIOS S.R.P. (Single Responsibility Principle); Evita duplicação;
Manutenibilidade.
44
RULE #5: One dot per line
45
TRAIN WRECKS Robert UncleBob Martin
46
this.Repository.Database.Config.SetAttribute("attribute" , "value");
E se houver um null? 46
47
Null object?
48
POR QUE NÃO? Esconde um problema de encapsulamento;
Difícil de debugar e tratar exceções; O código deve ser reestruturado e tomar consciência da existência dele; Prejudica a leitura e o entendimento.
49
LAW OF DEMETER
50
this.Repository.SetDatabaseConfig("attribute", "value");
Nem sempre é aplicável 50
51
EXCEÇÕES Fluent Interface;
Builders (ex.: Query Builder, Link Builder, etc...);
52
BENEFÍCIOS Lei de Demeter; O.C.P (Open/Closed Principle);
Legibilidade; Testabilidade; Debug.
53
RULE #6: Don’t abbreviate
54
POR QUE ABREVIAR? Escrita repetitiva? Nomes muito longos?
“There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors.”
55
BENEFÍCIOS S.R.P. (Single Responsibility Principle); Comunicação;
Legibilidade; Manutenibilidade.
56
Keep all entities small
RULE #7: Keep all entities small
57
DIRETRIZES Classes com 50 linhas; Leitura com pouco uso de scroll;
Apenas desenvolva o que for utilizar.
58
BENEFÍCIOS S.R.P. (Single Responsibility Principle); Legibilidade;
Encapsulamento; Segregação; Coesão e Coerência.
59
No classes with more than two instance variables
RULE #8: No classes with more than two instance variables
60
ESSA É DIFÍCIL
61
List<String> names;
class Name { String first; String middle; String last; } class Name { Surname family; GivenNames given; } class Surname String family; class GivenNames List<String> names; 61
62
Por que somente duas?
63
COMPLEMENTAR A REGRA #2
64
BENEFÍCIOS S.R.P. (Single Responsability Principle);
Baixo acoplamento; Encapsulamento; Coesão e Coerência; Testabilidade.
65
No getters / setters / properties
RULE #9: No getters / setters / properties
66
POR QUE? Simplesmente uma questão comportamental.
67
public int X { get; set; } public int Y { get; set; } }
class Rectangle { public int X { get; set; } public int Y { get; set; } } Rectangle rectangle = new Rectangle() { X = 10, Y = 5 }; int area = rectangle.X * rectangle.Y; 67
68
TELL, DON’T ASK!
69
public Rectangle(int x , int y) this.X = x; this.Y = y; }
class Rectangle { private int X; private int Y; public Rectangle(int x , int y) this.X = x; this.Y = y; } public int TotalArea() return this.X * this.Y; Rectangle rectangle = new Rectangle(10, 5); int area = rectangle.TotalArea(); 69
70
BENEFÍCIOS O.C.P (Open/Closed Principle); Encapsulamento.
71
CONSIDERAÇÕES
72
QUESTIONS? Thanks!
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.