If your use-case is that the user can select the crust, sauce, cheese and toppings for a pizza, just pass that shit to the make_pizza function with the help of enums and arrays. If you want to have predefined pizzas, you'd simply make a dictionary of pizza templates with all the options that the make_pizza function needs and/or if you wanna be fancy, you'd make a separate make_pizza_from_template function, but definitely not a make_pepperoni_pizza function, because that's just encoding data as a code in a silly way that arguably not even a factory pattern.
No solution will be able to cater to requirements that don't exist at the time of developing this pizza-application. You build it according to the requirements that exist and that is enough. It's not your fault if nobody cared to mention that the user should be able to arbitrarily subdivide the pizza and select options sepatately for each subdivision - that's a feature update and it's OK if the original program hadn't though of that. Just like you wouldn't scaffold ecommerce capabilities into a webpage "just in case", if there had been zero mention of such a need.
It's a confused abstraction level: there must be a database of pizza "templates" (consisting of named menu items and of the lower level of pricing rules and admissible choices of crust, topping, etc.); it must be separate from generic pizza processing because it is subject to change over time; and conversely pizza processing must work for any configuration of that database, without special cases.
Mixing pizza database identifiers into generic pizza processing (e.g. make_ham_pizza) is wrong even without repetitions.
> It's not your fault if nobody cared to mention that the user should be able to arbitrarily subdivide the pizza and select options sepatately for each subdivision - that's a feature update and it's OK if the original program hadn't though of that.
I would argue it’s part of your job most of the time to challenge whatever needs are presented and ask questions about the long-term vision to find a good middle ground of future proofing vs over-engineering. That is of course one of the hardest things to get right.
You're right. At the risk of sounding kind of hypocritical, after a decently long career in software engineering, I've learned that some carefully chosen future proofing is one of the things that makes a great developer and it's also something where one learns to eventually "see" where it is needed.
My "if nobody cared to mention..." part should have probably said "if nobody cared to mention, even after several specification meetings, that the software should be able to do X..." as I agree it's definitely part of your job to assess the needs.
This post is a bit weird though. It's as if someone is ranting about how hard it is to hammer nails into wood with a shoe or 15 other things, when you could just use a hammer.
If your use-case is that the user can select the crust, sauce, cheese and toppings for a pizza, just pass that shit to the make_pizza function with the help of enums and arrays. If you want to have predefined pizzas, you'd simply make a dictionary of pizza templates with all the options that the make_pizza function needs and/or if you wanna be fancy, you'd make a separate make_pizza_from_template function, but definitely not a make_pepperoni_pizza function, because that's just encoding data as a code in a silly way that arguably not even a factory pattern.
No solution will be able to cater to requirements that don't exist at the time of developing this pizza-application. You build it according to the requirements that exist and that is enough. It's not your fault if nobody cared to mention that the user should be able to arbitrarily subdivide the pizza and select options sepatately for each subdivision - that's a feature update and it's OK if the original program hadn't though of that. Just like you wouldn't scaffold ecommerce capabilities into a webpage "just in case", if there had been zero mention of such a need.