Re: Multiple front-ends in project
dn via Tutor <[email protected]>
| Newsgroups | gmane.comp.python.tutor |
|---|---|
| Organization | DWM |
| Message-ID | <[email protected]> |
On 28/06/2023 05.04, trent shipley wrote: > Middle posting Responses interposed (posh talk!) > On Sun, Jun 25, 2023 at 5:34 PM dn via Tutor <[email protected] > <mailto:[email protected]>> wrote: > > On 24/06/2023 12.50, Alan Gauld via Tutor wrote: > > On 23/06/2023 18:11, trent shipley wrote: > >> I have written the simple core logic for a dice rolling > program. It is In > >> ./app/core. I am planning to add more complex helper classes in > >> separate files to do more complex things like rolling different > kinds of > >> dice in one throw, or exploding dice. > >> > >> I plan four interfaces, two CLI, and two GUI. > > Further to @Alan's analysis, (although not being aware of your level of > ComSc/DataSc expertise) I regularly remind/put the 'circles' diagram in > front of trainees > (https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg <https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg>) > > > The diagram was very useful, especially the little diagram in the lower > right corner. When looking at the code, does EVERY class and function fit (only) into one of those 'circles'? The same question is probably applicable to each fitting into either one of the two CLI or one of the two GUI 'front-ends' OR is part of the actual dice-simulation 'core code'? If not, recommend some refactoring... > This illustrates that the code fulfilling the purposes of the outer > 'circles' needs to know (a limited amount of) what's going-on 'inside', > but the inner-circle(s) don't need to know where data is coming-from or > going-to! (paralleling @Alan's "MVC" ideas of 'separation') > > > I have an unfortunate habit of designing bottom-up despite having been > taught to favor doing it the other way around. No! Bottom-up can't be "design". One can't draw a jig-saw puzzle's picture by painting on successive pieces before they are assembled into the whole! In this case, you can identify your four front-ends, and a computational-core. Thereafter you could ignore all of those components except the last, and design that in more detail - only coming back to designing the others after implementation of the core. (but that's not "bottom-up") You can break-down the details of the core, 'layer by layer', each more precise than the other, until you're ready to code - and can imagine how all of that (piece of the) code will fit together. Coding can then be a bottom-up process: - a function to roll a single, six-sided (traditional) die - expand to roll the die multiple times - enhance to a variable number of 'sides' - upgrade to consider multiple dice ... That is an iterative process. Even better if, each time, you can add controlling functions which fit around the basic process! If you can keep the code modular (which in Python usually means classes and functions - with modules, perhaps when start adding the four front-ends into the picture) this will make iteration easier. Also, testing as you go solves the problem of 'where did that error actually arise' (cf where it became manifest). OK, I suspect that this was a project which started-out as a topic for learning (some) Python. In which case, 'design' was not front-of-mind, and something, perhaps the random library, was the focus of attention. No criticism! There comes a time though, when the aggregation of various ideas, inspirations, desires, imaginings, and experiments (bottom-up) starts to smell like 'warts have been grafted onto the back-side of carbuncles'. In which case, starting with a fresh sheet of paper/wiped whiteboard, and re-imagining a solution is likely the best path forward*. By this stage, one's Python knowledge has increased, and one's domain-expertise has grown. Consequently a 'design' is now possible (if not, necessary) whereas it was not before - or not the primary mission earlier. Either way, the design becomes a top-down view, starting with (perhaps) a single sentence, and becoming more and more detailed as the 'layers' become more precise. * which is not to say that you won't re-use chunks of code! Accordingly, I start with 'design' and follow the principle of stepwise decomposition. However, once coding starts, I work function-by-function, class-by-class (module-by-module!) and testing each unit as I go. I know which unit to start with, and which to code 'next' (and so-on) because 'the design' acts as a road-map. That process however, is very much bottom-up. Sometimes, when working at the code-face, it can be difficult to keep in-mind how this 'unit' plugs into the application as a whole. This is where 'design' helps one stay on the straight-and-narrow! Another aspect of 'design' (and bringing-up YAGNI/reining-in our native-enthusiasm) is that if one starts with an "MVP", then it helps us to follow the maxim "make it work before you make it 'better'!". To borrow from Fred Brooks (Architect of IBM's System/360 project), constraints can be our friends! Are you getting the feeling that no 'one size' will fit all? > If interested, please see-also theories such as "Separation of > Concerns" > and the "SOLID Principles", specifically the "Single Responsibility > Principle". In short, if the description of the work performed by a > single unit of code (eg function, class, ...) features the word "and", > then that code may contain a 'gotcha' for exercises such as this! > > > Accordingly, the code which actually includes a call to the > random-library does not need to know if the request has come from a > user > using a GUI or the CLI. Yes, other 'outer' logic can take care of > that - > and ensure that a request from the GUI will return the results in > similar fashion rather than printing to the 'command-line'. > > Considering the 'center' in a bit more detail: what data does the 'core > logic' require from its "External Interface" (regardless of which one)? > > This may include: > - how many sides to the die/dice > - how many dice > - home many rolls > ... > > Indeed. > > This is the "API" (Application Programming Interface). More > prosaically, > it is probably the 'signature' of one of the existing functions in the > system. (which is another way of getting rid of the high-falutin > terminology) > > > Yes the dice rolling logic is accessible and is what middle layers would > access. > > Once you've identified ("finalised") this, then turn your attention to > the GUI and CLI components. The 'input' part of these must be built to > be as pretty and/or as workable as is appropriate, but ultimately must > provide the information required by the (above) API/signature. > > > Is it OK to work on this iteratively, rather than trying to pin down the > needed 'business' logic and functions in one go? Sure, but... If the business-logic is updated 'internally' - for example swapping one PRNG for another, then no-problem. If you implement (say) a routine which deals with six-sided dice, and then build the four 'front-ends', everything will be fine-and-dandy. However, if you now enable multi-sided dice, not only does the 'business logic' have to be updated, but so too must each of the front-ends. Thus, the cost of change is much higher. However, you have an MVP up-and-running. Now, if you factor-in the idea that until users can actually see 'something' (today marketing-folk use the word "experience") they won't know that they want something different, bigger, brighter, better, faster, in pink, with racing-stripes, ... Once again, I'll preach the principles of 'design', of modular programming, and "structured programming". If your solution has been built with 'change' in-mind - which is somewhat similar to building-in every little option, except that you don't actually, you only build what is there, with the idea that extensions may/will come at some future stage. Flexibility... Open-Closed Principle... > The same, in-reverse, for output... > > > Referring back to the diagram. The die/dice is an "entity". The number > of sides per die is a "business rule" (the 'business' (ahem) of > statistical distribution). The "Use Cases" are the varieties of > simulations you'd like the dice to be used to perform. The > Web/UI/External Interfaces encompass many of your existing > explanations/intent. > > > Have enjoyed considering the question. Some additional comment (FWIW): > > Further to @Alan's "waffle", may I recommend the "YAGNI Principle", ie > don't 'put stuff in' until you actually receive a solid use-case for it > (in my case: I don't do things until the client has agreed to pay for > them). Just because it might be useful - or might be fun to code-up, is > not a solid reason (it *is* a reason (professional responsibility?) to > go back to the client and ask if (s)he agrees - *and* is prepared to > pay > for it!). Most of the time it represents a delay to 'delivery' because > You/They Ain't Going To Need It! > > When I build software at work, I have a horrible problem with gold > plating, so KISS and YAGNI are real issues for me. The killer app I > imagined was a dice roller for RPGs with a GUI front end I could > actually use and tinker with. The CLI version I'm working on now may > not have too much utility, And the 'advanced' or 'scientific' versions > are solutions looking for consumers. Professionalism includes discipline! Isn't dice-rolling a fairly standard intro-to-writing-code in stats courses? (was in mine - coins and dice illustrating random processes, counting, distributions, ... > Am also anticipating you will have to put in some 'rework'. Recommend > that you start with (unless you have them already) a set of tests (a > 'testing framework'). This will 'prove' (in the logic/mathematical > sense) that the existing code works correctly. This is a 'stable > state'. > Now, when something is 'reworked' in order to separate the components > and create the API (between External Interfaces and the Entities and > Use > Cases/Controllers), the tests will continue to pass - or will fail and > thereby show that the 'new work' has introduced an error (which, one > way > or the other) will need 'fixing'! It seems like more (even, > unnecessary) > work up-front, but may pay greater dividends over time... > > There are some tests. They pass. I don't trust them. I've been an > SDET for functional testing of web and Windows GUIs, but have only very > recently needed to work with unit and parameter tests. Here's another personal bias: TDD - and make sure the tests are worthwhile (what point otherwise?) A potential client called for help today with a data-capture and Python problem - "it has suddenly stopped working/crashed". One of my early questions was 'what tests do you have?'. You can guess that answer... (see also conversation 'here' about using modules to better locate/isolate steps in the application, and thus locate the sources of errors) The 'good news' about unit-testing Python code is that you can use (straight-line code) Python, eg pytest. Compared with GUIs where one might have to also learn and use Selenium, or similar! > Yesterday was Scala day, today is Python day. > > Looking forward to hearing how the project progresses... -- Regards, =dn _______________________________________________ Tutor maillist - [email protected] To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor