Someone on Slack shared https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition, which is absolutely bizarre. It’s similar to some aspect of capitalism, with a tasted mixed by reality and irony.
Anyway, it got me thinking how would I approach this problem today. So I gave it a try in https://github.com/dayfine/fizzbuzz2022. Apparently this doesn’t need to go “Enterprise” level but it should demonstrate the characteristics we value most as a software engineer.
The most important thing that came to my mind is definitely composability, which is one of the important tools to keep software soft. I noticed that the functions that individually handle the Fizz and Buzz cases have the same type with the FizzBuzz function, which means this function type as well as its return type are Monoids. Then it’s simply a matter of defining the types and how these types combine as Monoids.
The resulting code is as followings:
from typing import Callable, ListProduceFn = Callable[[int], str]def combine_strs(inputs: List[str]) -> str:
return ''.join(inputs)def divisible_by(k: int, n: int) -> bool:
return n % k == 0def produce_if_divisible_by_fn(output: str, k: int) -> ProduceFn:
return lambda n : output if divisible_by(k, n) else ''def combine_produce_fns(fns: List[ProduceFn]) -> ProduceFn:
return lambda n : combine_strs([fn(n) for fn in fns]) or f'{n}'fizzbuzz: ProduceFn = combine_produce_fns([
produce_if_divisible_by_fn('Fizz', 3),
produce_if_divisible_by_fn('Buzz', 5),
])
This makes adding additional rules relatively simple, say we want to have another string output when the input number is divisible by 7. If the condition ever goes beyond divisibility, it would be possible to parameterize the condition checking function as well.
The ability to make a program composable in order to make it software and evolvable is something I pay great attention to in my work. For everyday programmers, this ability would be much more important than making your program “enterprise-level”.