Last active
March 3, 2025 16:29
-
Star
(0)
You must be signed in to star a gist -
Fork
(230)
You must be signed in to fork a gist
-
-
Save sizovs/927a445203f885547976ef36fa0a978b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1. Fix bad naming. | |
class ShoppingCart { | |
UUID getShopingCartId() { ... } | |
boolean checkFreeShippingEligibility() { ... } | |
void removeOrderItem(OrderItem orderItem) { ... } | |
void addOrderItem(OrderItem orderItem) { ... } | |
Collection<OrderItem> getOrderItems() { ... } | |
} | |
// 2. Eliminate noise. | |
void openNewBankAccount() { | |
var bankAccountWithdrawalLimits = WithdrawalLimitFactory.defaultWithdrawalLimits(); | |
var bankAccountHolder = new BankAccountHolder(...); | |
var bankAccount = new BankAccount(bankAccountHolder, bankAccountWithdrawalLimits); | |
bankAccount.openAccount(); | |
bankAccount.depositAmount(clientSignupBonus()); | |
bankAccountRepository.add(bankAccount); | |
} | |
// 3. Inline nesting is hard to reason about, as it doesn't convey the transformation order. Please refactor. | |
String normalize(String fullName) { | |
return stripEmojis(stripAccents(capitalize(fullName))); | |
} | |
// 4. Refactor Member data class into an object | |
member.getAssignedOffers().add(offer); | |
member.setNumberOfAssignedOffers(member.getNumberOfAssignedOffers() + 1); | |
// 5. Find a missing domain object, and eliminate a meaningless domain object (service) with it. | |
class MortgageRiskService { | |
BigDecimal calculateRisk(MortgageApplication mortgageApplication) { | |
... | |
} | |
boolean isTolerable(BigDecimal risk) { | |
... | |
} | |
boolean areRisksEquivalent(BigDecimal oneRisk, BigDecimal otherRisk) { | |
... | |
} | |
} | |
// 6. Find a missing domain object, and meaningless domain object(s) with it. | |
class BankruptcyProbabilityCalculator { | |
BigDecimal calculate(Business business) { ... } | |
} | |
class BankruptcyProbabilityUtils { | |
boolean isHigh(BigDecimal decimal) { ... } | |
} | |
// 7. Find a missing domain object, and eliminate CsvParser. | |
class CsvParser<T extends Line> { | |
Collection<T> parse(File location) { | |
} | |
} | |
// 8. Find a missing domain object, and eliminate Pinger. | |
interface Pinger { | |
void sendPing(); | |
} | |
// 9. Find a missing domain object, and eliminate MoneyFormatter. Limitation: you can't change Money class. | |
interface MoneyFormatter { | |
String format(Money money); | |
} | |
// 10. Turn XmlMarshaller into a class Xml | |
// + Make the class generic (decouple it from Invoice) | |
// + Use try-with-resources block | |
// + Minimize noise | |
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. make class null-safe with Optionals, and replace a dumb setter with a domain-specific method. | |
class User { | |
private Permissions permissions; | |
void setPermissions(Permissions permissions) { | |
this.permissions = permissions | |
} | |
} | |
// 12. 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 | |
// 13. Can you spot a domain object that hides behind a BlacklistingService and refactor the code accordingly? | |
interface BlacklistingService { | |
boolean shouldBlockWebsiteVisitor(BlacklistRequest request); | |
} | |
record BlacklistRequest(String email, String ipAddress) { } | |
// 14. Introduce meaningful objects, and replace exception throwing with Monads. | |
interface AnonymousUserAuthenticator { | |
// returns authentication token or throws exception | |
String authenticate(String username, String password) throws AuthenticationFailed; | |
} | |
// 15. 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(); | |
} | |
} | |
// 16. Can you stop mixing method refences with lambdas and SLAP (Single Level of Abstraction Principle) the code? | |
boolean destroyButtonAvailable = | |
widgets | |
.stream() | |
.filter(Widget::isButton) | |
.filter(button -> button.label().equals("Destroy The World")) | |
.findAny() | |
.isPresent(); | |
// 17. | |
// 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() { | |
// ... | |
} | |
} | |
// 18. Checked exceptions don't work well with lambdas, and the Java community has largely moved away from using them. | |
// Unfortunately, sometimes checked exception come with legacy code we cannot change. | |
// Do you know how to fix this w/o modifying the Port class? | |
int availablePort = IntStream | |
.rangeClosed(8000, 9000) | |
.filter(num -> { | |
try { | |
var port = new Port(num); | |
return port.isAvailable(); | |
} catch (IOException exception) { | |
throw new RuntimeException(exception); | |
} | |
}) | |
.findFirst(); | |
// 19. Can you make SecurePassword fetch the remote Vault lazily when toString() is called, | |
// ensuring the same password is returned on subsequent calls to toString()? | |
class SecurePassword { | |
private final String password; | |
private SecurePassword(Vault vault) { | |
this.password = vault.verySecurePassword(); | |
} | |
@Override | |
public String toString() { | |
return password; | |
} | |
} | |
// 20. Well done! Have a break! 🎉 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment