Skip to content

Instantly share code, notes, and snippets.

@sizovs
Last active November 12, 2023 14:11
Show Gist options
  • Save sizovs/927a445203f885547976ef36fa0a978b to your computer and use it in GitHub Desktop.
Save sizovs/927a445203f885547976ef36fa0a978b to your computer and use it in GitHub Desktop.
// 1. refactor the code so it's at the same level of abstraction (SLAP).
int from = 8000;
int to = 9000;
int availablePort = IntStream
.rangeClosed(from, to)
.filter(num -> {
try {
var port = new Port(num);
return port.isAvailable();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
})
.findFirst();
class Port {
// throws IOException on a network connection failure.
boolean isAvailable() throws IOException {
...
}
}
// 2 Refactor code to a higher (and single) level of abstraction
class Registration {
private final RegistrationForm form;
private final Repository repo;
Registration(RegistrationForm form, Repository repo) {
this.form = form;
this.repo = repo;
}
void complete() {
if (isEmpty(form.username()) || isEmpty(form.password()) {
throw new RegistrationException(MISSING_CREDENTIALS);
}
var username = new Username(form.username());
var isUsernameTaken = username.satisfies(new IsTaken(repo));
if (isUsernameTaken) {
throw new RegistrationException(USERNAME_TAKEN);
}
var password = new Password(form.password());
var isWeakPassword = password.satisfies(new IsWeak(repo));
if (isWeakPassword) {
throw new RegistrationException(WEAK_PASSWORD);
}
var user = new User(username, password);
user.save(repo);
DomainEvents.publish(new RegistrationCompleted(user));
}
}
// 3. eliminate getters and setters and turn Member data class into an object
member.getAssignedOffers().add(offer);
member.setNumberOfAssignedOffers(member.getNumberOfAssignedOffers() + 1);
// 4. Find missing domain objects and reify (thingify) them.
borrower.applyForALoan(BigDecimal amount, int term, Map<LocalDateTime, Id> existingLoansByDate);
// 5. Find a missing domain objects and reify (thingify) it.
class MortgageRiskService {
BigDecimal calculateRisk(MortageApplication mortgageApplication) {
...
}
boolean isTolerable(BigDecimal risk) {
...
}
boolean areRisksEquivalent(BigDecimal oneRisk, BigDecimal otherRisk) {
...
}
}
// 6. Find a missing domain objects and reify (thingify) it.
class BankruptcyProbabilityCalculator {
BigDecimal calculate(Business business) { ... }
}
class BankruptcyProbabilityUtils {
boolean isHigh(BigDecimal decimal) { ... }
}
// 7. Find a missing domain object (hint: CsvF...) and eliminate an agent class CsvParser.
class CsvParser<T extends Line> {
Collection<T> parse(File location) {
}
}
// 8. Find a missing domain object and eliminate an agent class Pinger.
interface Pinger {
void sendPing();
}
// 9. Find a missing domain object and eliminate an agent class MoneyFormatter.
interface MoneyFormatter {
String format(Money money);
}
// 10. Turn XmlMarshaller into a class Xml
// + Make the class generic (decouple it from Invoice)
// + Use type inference
// + Use try-with-resources block
class XmlMarshaller {
byte[] marshallToXml(Invoice invoice) {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
JaxbMarshaller jaxbMarshaller = new JaxbMarshaller(Invoice.class);
jaxbMarshaller.marshallObject(invoice, outStream);
byte[] resultXml = outStream.toByteArray();
IOUtils.closeQuietly(outStream);
return resultXml;
}
}
// 11. Fix a bad method naming.
interface Input {
boolean validate();
}
// 12. make Permissions "optional", and replace a dumb setter with a domain-specific method.
class User {
private Permissions permissions;
void setPermissions(Permissions permissions) {
this.permissions = permissions
}
}
// 13. Can you resolve a naming conflict? no getters & setters allowed!
user.ban() // returns user's ban and the corresponding information (if any)
user.ban() // bans a user
// 14. Can you spot a domain object that pretends as a BlacklistingService and refactor the code accordingly?
interface BlacklistingService {
boolean shouldBlockWebsiteVisitor(BlacklistRequest request);
}
interface BlacklistRequest {
String getEmail();
String getIpAddress();
}
// 15. Turn this agent noun into an object "AuthenticationToken"
interface AnonymousUserAuthenticator {
String authenticate(String username, String password) throws UserDoesNotExistException; // returns authentication token
}
// 16. fix different naming issues
interface Suite {
interface SuiteTest {
void print();
boolean successfulTest()
}
void runAndWait();
Collection<SuiteTest> listSuiteTests();
}
suite.runAndWait()
for (SuiteTest suiteTest : suite.listSuiteTests()) {
if (!suiteTest.successfulTest() ) {
// pretty printing
suiteTest.print();
}
}
// 17. Can you SLAP (Single Level of Abstraction Principle) it?
boolean destroyButtonAvailable =
widgets
.stream()
.filter(Widget::isButton)
.filter(button -> button.label().equals("Destroy The World"))
.findAny()
.isPresent();
// 18.
// implement the /fullName/ method so that it:
// 1. returned "firstName lastName" if nickname is missing
// 2. returned "firstName <nickname> lastName" if nickname is present.
// For example: "Robert Martin" or "Robert <Uncle Bob> Martin"
class User {
private final Optional<String> nickName;
private final String firstName;
private final String lastName;
String fullName() {
// ...
}
}
// 19.
// from variable names, omit words that are deductable from the context
void openNewBankAccount() {
var bankAccountWithdrawalLimits = WithdrawalLimits.defaults(env);
var bankAccountHolder = new AccountHolder(...);
var bankAccount = new BankAccount(bankAccountHolder, bankAccountWithdrawalLimits);
bankAccount.open();
bankAccount.deposit(openingBonus());
bankAccountRepository.save(bankAccount);
}
// 20. Nesting is pretty hard to reason about, as it doesn't convey the order of transformations.
// Can you refactor the code to eliminate nesting?
private static String normalize(String fullName) {
return removeAllEmojis((capitalizeFully(stripAccents(fullName))));
}
// 21.
// calling a logic (such as remote system call) in a constructor is not always a good idea. Do you know how to fix that?
class SecurePassword {
private final String rawPassword;
private SecurePassword(Vault vault) {
this.rawPassword = vault.verySecurePassword();
}
public String raw() {
return rawPassword;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment