[HN Gopher] In Praise of Top Down Programming
___________________________________________________________________
In Praise of Top Down Programming
Author : kiyanwang
Score : 72 points
Date : 2023-04-10 08:40 UTC (1 days ago)
(HTM) web link (www.i-programmer.info)
(TXT) w3m dump (www.i-programmer.info)
| brandly wrote:
| That site's layout is like 80% ads, 20% content!
| chankstein38 wrote:
| In my more complicated personal projects, I'll usually do this in
| comments in the code. Basically pseudocode to just expand out and
| then I'll either write things in between the comments that
| actually add the functionality or I'll just leave it at the top
| as a kind of "this is what this iteration does" because I'll also
| frequently complete an idea and then I'll have some other idea
| with it that requires refactoring and I'll make my second file
| etc!
| rvr_ wrote:
| For the "play chess" example a state machine is the perfect place
| to begin modeling. Games, as a rule, are event-driven and are
| commonly coupled to a event-loop that triggers the transitions of
| the state machine. I think top-down decomposition has it's place,
| but the examples used to describe it should be given a little
| more thought.
| mkehrt wrote:
| I think the advantage of chess for something other than top
| down programming is that you're pretty much 100% what the API
| you want for the chess state machine is before you start. But
| how common is this?
| nine_k wrote:
| "Everything should be built top-down, except for the first time"
| (from Perlisms, 1970s or so).
|
| Approaches to neatly building a well-understood thing are
| radically different from approaches to building / tweaking /
| rebuilding a new, so far untried thing.
|
| Software engineering is most valuable around the latter kind of
| thing; the former kind of thing is usually already built and
| open-sourced.
| hinkley wrote:
| How often have you gotten to build things for the second time?
|
| The dilemma there is that most of us only get to build things
| for the second time if we are working on a copy-cat product
| from a competitor, and those are not the sorts of projects we
| glorify. Everyone wants to work on new ideas, not copy-cats.
| tabtab wrote:
| "Stepwise refinement" is an intuitive and powerful concept, in
| part because it helps you grok and debug in a "fractal" kind of
| way, level by level. But it does have limits at a larger scale.
| (Event-driven architecture is often better for big.)
|
| It's something Functional Programming either lacks or doesn't do
| as smoothly. The intermediate results and state are highly useful
| for debugging, and Functional doesn't "like" intermediate state.
| Yes, it can be emulated, but the emulation is rarely good as the
| real thing. For one, the emulated state lacks useful variable and
| token names, because it's machine-generated.
| Ma8ee wrote:
| Functional doesn't like _state_. That's the whole point.
| Functions that can be run in isolation with well defined input
| is much easier to debug.
| tabtab wrote:
| In theory. Practice has proven messier to many. Maybe some
| have a "functional mind", but they shouldn't extrapolate
| their head to others. Functional has been around for 60+
| years. If it were the magical productivity and Lego-
| modularity golden hammer, it would have mainstreamed already.
| (Long LINQ is also hard to debug for many of us.)
| Ma8ee wrote:
| It is becoming mainstream. Not by pure functional languages
| taking over, but by developers adopting a functional style
| and by better and better support for functional programming
| in mainstream languages.
| tabtab wrote:
| I'm not sure I'd agree. A lot of the use-cases are for
| niches or systems programming. I don't see it for
| business CRUD that often unless either the framework
| forces it on one, or they are using LINQ, which as I
| pointed out, can be tricky to debug if long. SQL is
| largely functional, but it's also hard to debug. The
| addition of the WITH clause to SQL greatly helped, as one
| can paste sections to test. Still, not as x-ray-able as
| imperative. Imperative still wins most x-ray contests.
| Maybe fast code readers don't need debugging as often?
| Could be, but I'm average at it.
| ParetoOptimal wrote:
| > The intermediate results and state are highly useful for
| debugging, and Functional doesn't "like" intermediate state.
|
| s/foldr/scanl
|
| Only sort of kidding. Can you give aconcrete example of some
| task you'd like intermediate state around?
|
| Also, do you know about the validate monad?
| tabtab wrote:
| x = foo01(); y = foo02(x); z = foo03(x,
| y);
|
| Contrast with: foo03(foo01(),
| foo02(foo01()) );
|
| x, y, and z were named by humans, giving them domain meaning,
| whereas a debugger would give the second one no name or
| machine-made names for intermediate state. (Here, z, y, and z
| have no meaning because it's a foo-bar example, but in
| practice they'd have better names.)
|
| The first is also often easier to read than the second, at
| least to my eyes. I know devs who can read the second
| quickly, but I don't think it's the norm. The LINQ "dot
| style" can be a little easier to read, but has similar
| problems.
| garethrowlands wrote:
| Your first example is just as functional as your second.
| And, quite possibly, better style.
|
| But your overall point is fair. A function, once composed,
| curried or having captured data, is very much like an
| object. Indeed its representation in memory is likely very
| similar to an object (mostly functional languages) or
| actually identical (Java). Your debugger won't show the
| data in such a function but it's happy to show the data in
| an object. That's a big advantage of objects over
| functions. Hopefully debuggers will get better at this
| eventually.
| ParetoOptimal wrote:
| This example: x = foo01(); y =
| foo02(x); z = foo03(x, y);
|
| could easily be written in Haskell as:
| let x = foo01 y = foo02 x z = foo03
| x y in z
|
| My thinking is that functional languages don't preclude you
| from having intermediate state, but I will agree that
| composition is used often.
|
| Typically when working in a repl I don't really miss the
| intermediate state because my debugging consists of:
|
| The lambdas must flow. l> foo01 "expected result" l> foo02
| "UNexpected result"
|
| Then I'll debug foo02 in isolation.
|
| > foo03(foo01(), foo02(foo01()) );
|
| I think I'd write this as the let example above with
| variables. Otherwise I guess I'd need to use something
| like: foo03 foo01 . foo02 $ foo01
|
| Here's a Haskell playground link with these examples if
| you're curious or had something else in mind and want to
| modify the example: https://play.haskell.org/saved/MeRGyCjr
| Ma8ee wrote:
| > Here, z, y, and z have no meaning because it's a foo-bar
| example, but in practice they'd have better names
|
| As would foo0x.
|
| I don't think many functional programmers would object to
| writing code as you did in your first example if you think
| it improves readability and if you don't change what the
| names refer to.
| sumosudo wrote:
| Meh. Just Common Lisp. Have your cake and eat it from the top or
| the bottom, at the same time?! mmmm, maybe a new paradigm is in
| order ;)
| lebuffon wrote:
| Forth will echo your "Meh". How much of top-down is because
| bottom-up is so @#$%! hard in non-interactive languages.
| Jtsummers wrote:
| In a non-interactive language, you need to create a "harness"
| (aka, a program) to run your lower level functions (here I
| mean in the "top-down" sense of functions at the bottom of
| the call tree) independently. A test framework could
| accomplish this, and so you'll see people who do a more TDD-
| inspired approach will have an easier time conceiving of how
| to develop their program from the bottom-up. If you don't
| have a test framework or other framework assisting you then
| you end up writing "throwaway" programs (I often don't throw
| these away, they become utility programs when I'm done,
| though more for diagnostics and testing than for end users).
| People see that as wasteful, so they don't do it even if it
| might speed things up for them because it gives them earlier
| validation of their design and requires less rewriting if
| they find their design is invalid.
|
| Interactive systems like CL and Forth (as it's commonly
| implemented) give you that framework for free, it's already
| written. So why not take advantage of it?
| gashmol wrote:
| Pure Top down only works for small problems or problems you
| already know how to solve. Its main issue is that you don't know
| whether the solution is correct until you reach the bottom.
|
| Structured Design, which is a quasi top down method, works better
| in real life. Its main issue is that it didn't survive the OOP
| hype.
| tyingq wrote:
| _" Object-oriented design isn 't top-down, even when it pretends
| to be. The decomposition provided by objects is a model of the
| real world, which is after all where the idea originated"_
|
| I've seen plenty of code in "OO" languages that is just the sort
| of top-down imperative function type thing being described in the
| article. That is, people using OO solely to encapsulate state and
| variable scope, using methods more like functions, versus trying
| to model the real world as objects. I suppose though, that's not
| "OOD" then?
| sdze wrote:
| Isn't true OOP about Messaging and not about modeling objects
| of the real world?
| PhilipRoman wrote:
| Like many other religions, OOP has split into several
| competing factions, each with a slightly different
| interpretation. To complicate the situation even more, in
| many areas of the world OOP has been mixed thoroughly with
| the local pre-OOP beliefs from the dark ages.
| slowmovintarget wrote:
| True OOP believers must necessarily code in Eiffel. /s
|
| Bertrand Meyer's book Object-Oriented Software Construction
| is just about as good as it gets for defining and
| justifying OOP. Still worth a read today. That said,
| functional programming and hexagonal architecture are
| probably more useful.
| tabtab wrote:
| I found a lot of holes in the justification. The
| scenarios make a lot of questionable assumptions about
| how the future will change. I'll see if I can find a
| certain critique that used to be floating around the
| web...
| [deleted]
| gloryjulio wrote:
| The most usual patterns I have seen r using interfaces instead
| of inheritances and tagged union, and that's pretty much about
| it
| lightbendover wrote:
| I don't think I would trust any system that focuses purely on
| modelling the real world.
| hinkley wrote:
| We often have to model legal constructs. Short of working for
| organized crime there is really no way around it.
| guhcampos wrote:
| I have the feeling that TDD-oriented people like me tend to do a
| lot of top-down, at least mentally. I'll frequently write the
| general behavior (in my case either the API or runtime params and
| inputs) then work my way down to make it work.
|
| Somewhere in the middle, however, we all need to go down the
| layers to either store something in a database or figure out how
| to work on a collection of items. This turns the process bottom-
| up to some extend.
|
| Then the very last phase is going back and forth until both
| solutions meet in the middle.
| hinkley wrote:
| It's a constant problem with trying to talk about process. It's
| much easier to see the struggles of others, and not your own.
| I've had a couple bosses who probably could write a book on
| management, but to a man, their thesis about what makes them
| successful and which bits are necessary always misses some
| critical piece, usually lamented in private amongst the senior
| people.
|
| One of these, talking about his own mentor, asked me once,
| rhetorically, "is he successful because of his theories, or
| because he uses the same people on every project?" Wish that
| some of my previous bosses were that aware. They didn't always
| see the detailed work their senior people were doing to keep
| the wheels on. You always assume they see that about you when
| it comes to who they chose to report, but to hear them
| enumerate the virtues of the team, and omit such things, that
| stings.
|
| There are certain fictions we engage in different strategies
| for solving problems as well, and there's always a little
| Socratic method in the middle where we pretend like we haven't
| seen the solution at the end, and go through a farce of
| arriving at it step by step. That may reduce the importance of
| sudden epiphanies, but it does not remove it.
| cardboardbach wrote:
| [flagged]
| BiteCode_dev wrote:
| I usually champion the "let's start with the UI" state of mind in
| every company I go.
|
| This has several benefits:
|
| - it forces to confront reality of the problem and field
|
| - you have to talk to people, and understand their needs
|
| - you almost get your backend public API out of it for free
|
| After that, you don't really need to do full top down, you can
| split in subsystems, and works on small parts of those
| subsystems.
|
| It doesn't have to be a good looking or sophisticated UI. It can
| be a ugly, as long as it's practical and validated by the end
| user.
|
| But this works only well the if the problem can be well defined
| and you know how to solve it.
|
| If you need to figure it out, top down doesn't work as well.
| MrLeap wrote:
| A downside to this is that some types of stakeholders lament
| the apparent glacial state of progress backfilling a UI with
| functionality.
|
| A tick/tock of UI/functionality keeps those people from getting
| depressed during demo meetings.
| BiteCode_dev wrote:
| If you have demo meetings that matter, you likely have a
| designer, in that case the UI won't be ugly.
| lightbendover wrote:
| Demo meetings that matter, now that's an anti-pattern if
| I've ever heard one. Only UI work makes for a snazzy demo,
| anything else will bore stakeholders to tears (and you of
| course need stakeholders if the meeting matters). The
| backend can be completely mocked out and stakeholders
| wouldn't even realize. All demos do is bely progress and
| make milestones seem closer or farther away than reality.
| The only "demo" that matters is the actual product launch.
| sdze wrote:
| I coach Product Owners the same way when trying to create a
| backlog.
| retrocryptid wrote:
| I know it's passe, but I generally like to start with a set of
| requirements first. In the old days, when we were doing XP
| instead of agile, we didn't feel the pressure to "code
| something, anything." Now, unless I check in a couple thousand
| lines of code per day people think I'm slacking.
|
| But... not trying to say "build the UI first" is a bad choice
| if it works for you. I do mostly backend work on "high trust"
| transactions, so I tend to look at the API first and see if it
| matches the requirements i have at the time.
| cestith wrote:
| For some applications, like an API-driven backend made to
| serve other applications, you can consider that the API
| itself really is your UI. It's how your users interface to
| your code. Your users just happen to be other developers
| whose code had it's own UI too, maybe a text or graphical one
| or maybe another API.
| retrocryptid wrote:
| Good point. I was interpreting "UI" as "GUI".
| tabtab wrote:
| A good many times the customer doesn't spot important issues
| until they see it in a UI, preferably interactive. The design
| process is done best with a _combination_ of formal written
| requirements and mockups /demos.
| jugg1es wrote:
| I have always had great success when systems are designed from
| the UI first. It really helps you break a new business case
| down to the point where the backend code just starts writing
| itself.
|
| I suspect you are coming from a design background because
| people who have never built a UI before are always very
| suspicious of this suggestion.
| BiteCode_dev wrote:
| I don't come from a design background but my father drilled
| into my skull that nobody cared about my beautiful skills at
| work. They cared about their problems and if I could solve
| them.
|
| Coding just happen to be a mean to solve their problems, but
| they don't understand code, and I don't understand their
| problem.
|
| After a lot of frustrating client/dev interactions, I came to
| read "don't make me think" from Steve Krug. I realized the UI
| was the only language I shared with my customers to start a
| meaningful discussion.
|
| This turned out to work well, and got me paid, so I sticked
| to it.
| beached_whale wrote:
| This is how I start with libraries. How do I want to use it,
| and start with some code that will eventually compile. It acts
| as an integration test too. But this starts to expose issues
| earlier with my understanding. Then if the interface doesn't
| work, it's easier to fix earlier.
| bakul wrote:
| There is a third way: define, explore and build a model of the
| problem space your program is supposed to be addressing. This
| forces you to understand its properties much better. Once you
| understand it better you can likely implement in any of the
| common programming languages. This is also why I like languages
| like Scheme or APL or k for exploration.
|
| Often the UI addresses only a subset of this space -- it is only
| the _visible_ part of the iceberg as it were! There is a lot
| going on under the UI surface. Not to mention you may want more
| than one (kind of) UI.
| leobg wrote:
| Sounds interesting. Can you give or link to an example?
| zwieback wrote:
| It's not all one or the other, I'm more of a layer-at-a-time
| developer and within a layer development can be inside-out (start
| with an algorithm and add an interface) or outside-in (start with
| an interface and mockup, then add the internals later).
| cestith wrote:
| I mostly like to choose a data structure that's handy for
| modeling the data I'm worried about first. Then I write code to
| manipulate that data, including getting it into and out of
| other formats if necessary. Then I worry about what the
| application really needs to do with it. Once everything's a
| presentation or transformation of the central data structures,
| the code becomes fairly obvious. One I have the data handling
| and the UI, often the UI is just another case of presenting or
| updating the data.
| hinkley wrote:
| In a top-down vs bottom-up world, the Mikado Method is the
| middle-out approach.
| charlieflowers wrote:
| If I'm optimizing for my brain, my strengths, and my programming
| style, bottom up is better. With a particular focus on nailing
| down the hardest or murkiest part, then the next
| hardest/murkiest, and so on. This phase can be ugly code if that
| helps ... the point is to uncover unknowns and let points with
| the fewest degrees of freedom become the first stakes in the
| ground.
|
| When there are no particularly hard/murky parts left, it's top-
| down from there, and that let's you choose the approach for
| various portions of the solution (such as, this part will be pure
| functions, this part will be based around an arena allocation,
| etc.).
|
| Even though I mentioned both bottom-up and top-down, the 10,000
| foot summary is bottom-up, because it starts there and the most
| time is spent in that mode.
|
| Whenever I get away from that and go top down too early, I'm
| likely to run into some area that either gets reworked, or that I
| compromise on and _wish_ I could justify the time to rework it.
|
| (And also with the caveat that some things are simple enough you
| could do them any way you want, and those are good candidates for
| top-down, which also seems more comfortable for more junior
| devs).
|
| UPDATE: However, I completely agree with another commentor --
| start with the UI first! I don't think that contradicts bottom-up
| ... it's about fleshing out both the requirements and the
| _potential_ requirements.
___________________________________________________________________
(page generated 2023-04-11 23:01 UTC)