Prinsip “Tell, Don't Ask!” (TDA)

Prinsip ini diperkenalkan oleh sesepuh OOP Martin Fowler. “Tell, Don't Ask” (TDA) artinya adalah kita tidak meminta data dari objek lalu kita memutuskan apa yang harus dilakukan, melainkan kita memerintah objek untuk melakukan apa yang kita inginkan. Jadi, di sini objek yang bekerja untuk kita. Prinsip ini mencegah micromanage di luar objek agar eksekusi yang dilakukan objek lebih simple.
Pelanggaran TDA
Misalkan kita membuat logic untuk menarik uang dari tabungan. Codenya kurang lebih seperti ini:
@Getter
@Setter
public class Account{
private String username;
private BigDecimal balance;
}public interface AccountGateway{
Account findByUsername(String username);
void save(Account account);
}@RequiredArgsConstructor
public class AccountWithdrawalUseCase{
private final AccountGateway accountGateway;
public void withdraw(String username, BigDecimal amount){
Account account = accountGateway.findByUsername(username);
if(account.getBalance().compareTo(amount) < 0){
throw new IllegalStateException("Insufficient balance");
}
BigDecimal subtracted = account.getBalance().subtract(amount);
account.setBalance(subtracted);
accountGateway.save(account);
}
}Pada code di atas kita ambil data balance dari objek Account, lalu divalidasi, kemudian dikurangi balance tersebut sebanyak amount. Ini yang melanggar TDA, kita minta data balance lalu dikurangi dengan amount di dalam use case. Misalkan logic untuk pengurangan saldo dipakai di beberapa tempat seperti transfer, pembayaran, atau lainnya, maka logic tersebut bakal duplikat di mana-mana.
Solusi TDA
Jika menerapkan prinsip TDA maka codenya jadi seperti berikut:
@Getter
@Setter
public class Account{
private String username;
private BigDecimal balance;
public void subtractBalance(BigDecimal amount){
if(balance.compareTo(amount) < 0){
throw new IllegalStateException("Insufficient balance");
}
balance = balance.subtract(amount);
}
}@RequiredArgsConstructor
public class AccountWithdrawalUseCase{
private final AccountGateway accountGateway;
public void withdraw(String username, BigDecimal amount){
Account account = accountGateway.findByUsername(username);
account.subtractBalance(amount);
accountGateway.save(account);
}
}Di sini code untuk melakukan withdrawal kita pindahkan ke objek Account langsung. Di use case kita tinggal perintah doang untuk melakukan pengurangan saldo. Misalkan di use case transfer, pembayaran, atau lainnya juga ada logic untuk pengurangan saldo, maka ga perlu duplikat logic yang sama, tinggal eksekusi method subtractBalance() aja.
Verdict
TDA ini sejalan dengan prinsip Law of Demeter di mana sebuah unit ga boleh berinteraksi langsung dengan internal unit lainnya. Hal tersebut menyalahgunakan Encapsulation pada OOP. Selain itu dengan TDA duplikat logic jadi lebih berkurang karena kita bisa reuse logic yang sama. Untuk penggunaannya kita tinggal perintah aja dengan sebuah method. Menyuruh objek melakukan sesuatu lebih simple daripada meminta data dan melakukannya sendiri.
