Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I added my comments to the guidelines (only). #2

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Ormek
Copy link
Contributor

@Ormek Ormek commented Jan 19, 2025

My intend was to leave your text untouched, but I fixed 1 or 2 typos. I used quote markup for my stuff.

I still intend to add comments to the full essay, but this is all I managed today.
This should not be merged into main.

My intend was to leave your text untouched, but I fixed 1 or 2 typos.
I used quote markup for my stuff.
@Mauitron
Copy link
Owner

You bring up some very interesting points that warrant reflection. Give me some time to contemplate some of them before giving you an answer. I have a job interview tomorrow, so you can expect me to craft an answer after that.

@Mauitron
Copy link
Owner

I have a few questions so i can get a clearer picture not only of the problems
you might have brought to light, but also the perspective we are both viewing
it from. If there are any questions i will answer them aswell.

On Flow-Based Organization
Could you give an example of when artificial bounderies are necessery to
achieve a goal? It is not that i am completely disagreeing with you, it is more
the use of the word 'often'. I can only come up with a few reasons as to when
they would help, and half of them are due to time or scope of the project
rather than the code itself.

On Natural Bounderies
You bring up a really good point. The main problem with The River at this point
in time is it being new. It is not tested enough so we don't have enough
datapoints to assess the practical validity of some of the reasoned guidlines.
I do think the argument holds merit logically though, that is why i think it is
likely to work. The idea is to move away from the idea of shared cross-cutting
and focus on having the input or output of a function feed the required data to
whatever needs it. If it be populating a database or authenticate a password or
id. does that make sense?

On Flow of a Feature
Yes, at the end of the day this should be seen as a living document that has a
high probability to change when data is collected. I am sure things will be
modified or added in the future. to what extent i am unsure.

On Readability and Visitor Pattern
I must admit, this made me laugh. I can relate to this a lot. I have heard many
times how self explanitory an abstraction is, and suprise that i am confused.
The problem is the assumption of shared knowlage. it might be that, as you say,
it improve readability of the code for the tribe that created it, but it is one
of the reasons why complexity compounds over time. My asserstion would be that
understanding diverge as codebases and teams grow.

On Reuse
The thing the river tries to eliminate is global errors or bugs. if a check
exist in 99 distinct features, the bug must be very rare. I would at that point
argu that, firstly, it could be likely that the bug is only an issue in one of
the features, and secondly, it happens so rarely that time to fix all the rest
of 99 bugs is likely something that does not need to be hurried.

On Error Handeling
You highlight something very important. I am primarily a Rust developer which
makes me think about error handeling as something explicit. That being said, i
think the mental picture would me more that a river creates tributaries that
feed the computed data to its destination. If it feeds it into another river,
that river would most likely be the main river of the program. But there is
absolutely something that needs to be looked at more carefully.

On the Last Two Points
Do you mean how to design flows to contain and isolate failiurs and making
error states and recovery paths has not been shown/discussed in the essay well
enough? If so, this is a very good point that needs work, thank you! The same
is true for testing i think.

On Allowing and Dealing with Cross-Cutting Locally
In what way do you se this hiding the flow? si am thinking that if you have
logging and security within a linear function, those parts would output the
relevant data directly to where it is needed. avoiding moving data around. The
flow will be perserved because in the function, after you have written you
login info, there will be a bit of code that queries the database to see if it
should be accepted. Does that make sense?

On Following Idioms
I am unsure if I agree with you on this point. You are completely right at any
descrete point in time, but if we take the codebase and look at how it evolves
and gets interacted with through time, do you still think it holds true?

On Constant Complexity Scaling
The idea is that you maintain constant complexity by isolating the complexity
within functions. after a function has been called, it should not need any
other part of the system (hopefully) to deliver the feature it is designed for.
It is important to add that there might be requests for information and/or
manipulations to the database or state, but these, i guess, could be seen more
as lakes/oceans than rivers. They are the parts of the program where rivers
start from, or end at. Do i make sense?

On Proposals
I like your first and third suggestion better than my wording. i will be adding
it. On the other suggestion, on times when it might be necessery: I can see
management reasons as to why they are needed, they could save time that really
needs to be saved, but the cost of using them needs to be carefully weighed as
it compromisses the maintainability of the codebase, which could cost time in
perpituity.

Copy link
Contributor Author

@Ormek Ormek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added my reply to your comments whithout adding your comments into the text.

Feedback on your reply which I cannot relate to a text location:

On Natural Bounderies.

If it be populating a database or authenticate a password or
id. does that make sense?

Yes, it does make sene.

On Proposals

On the other suggestion, on times when it might be necessery:

I do not know, what you are refering to.

## Fundamental Principles

### 1. Flow-Based Organization
Code should be organized around complete flows of functionality rather than arbitrary technical boundaries. Each significant feature should be treated as its own "river", a coherent path from beginning to end. The goal is to maintain locality, visibility and comprehensibility of the entire process.

> If those technical boundaries are indeed *arbitrary* I fully agree. Often they are required by the techniques used. If those are strictly necessary to achieve the goal is another discussion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples are requirements like

  • test-ability (might require dependency injection to get a mock where it is required.
  • Extensability (Others should be able to extend/adapt the flow at runtime)
  • Consistency across flows (10 flows should behave similar)

@@ -20,28 +34,58 @@ Systems should be divided along natural feature boundaries, like a watershed con
4. Use clear section comments to guide readers through longer flows
5. Keep feature flows independent of each other where possible

> If *flow of a feature* is the only or main principle of structure, I fully agree. But, as I hopefully have commented in the main essay, I believe other principles are needed as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe your reply on this revers to the River-Guidelines yourself and that my comment means that is it not yet complete and should be extended.

My comment addresses something else. The whole "The River" approach assumes a certain main principle of structure. If I draw the program it will always be a flow-chart. My experience differs. In some applications the flow-chart is a good choice and the The-River is a good principle. It then makes sense to follow your guidelines.

But on other occasions other models are better suited to solve the problem. I have yet to elaborate on that and what other structures I mean.

4. Keep abstractions close to where they're used, preserving context
5. Accept similar patterns in different contexts rather than forcing reuse

> *Forcing* reuse does not make sense, agreed. If you scale the complexity of the problem domain, you will encounter the true *need* for reuse, because you will have to check 99 flows, if they also contain the bug you just fixed in 1 of 100 flows (I am aware that there are draw-backs on the reuse which might be harder to handle).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I accept your reply.

But, take a change in requirement. The resolution of the screen in use will change and those flows do contain actual pixel numbers (which could have been avoided in the first place, but have not). One flow contains: First column (100px) second column (150px) third column (remaining). When 500 pixels were available this is just fine. Now 1000 pixels are available. and I have to double those numbers.
Other flows handled the usage of the availble screen estate in their own independant way.

Contra Flow: How lovely it would have been if they all used a single shared parameterized screen, so I only had to change that one screen.

Pro Flow: How aweful it would have been if I had only a single shared parameterized screen to handle the requirements of 100 different flows. No one will understand the resulting parameters and any change to the screen might break many flows.

I had to deal with such a change for the Porsche Workshoptester.

2. Provide rich context in error messages by leveraging local knowledge
3. Design flows to contain and isolate failures
4. Make error states and recovery paths visible within the main flow

> I think the last two points have not been shown/discussed in the essay. If we were to discuss them, examples of what that means for you were required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean how to design flows to contain and isolate failiurs and making
error states and recovery paths has not been shown/discussed in the essay well
enough?

yes

### Cross-Cutting Concerns
1. Treat logging, security, and monitoring as part of the local environment

> This might hide the flow. How do you see/mitigate that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I mean: The flow in one of your examples is:

    // Parse the request
    // Validate the parameters
    // Query the database
    // Update the database
    // Construct the response

If you add logging, assertions, more checks for security and monitoring additions all this cross cutting concers will clutter up the function and hide the flow. I might not see the actual parsing in the code, because most of the code after the // Parse the request will no longer try to parse the request, but handle those other concerns.

3. Accept that similar patterns may repeat across different flows
4. Focus on clarity and completeness within each flow rather than global consistency

> Agreed, but: Global consistency can in turn increase readability across team members and thus maintainability. Following some idioms is ok.
If global consistency is required (e.g. You have to do C before A before B) to make things work, maintenance becomes hard (because people will "forget" to do C or A). Avoiding such global consistency completely, might impose abstraction (I hide doing C and A, from whoever does B) and might obscure the flow. Where to settle for compromise between those extremes is a matter of actual situation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you did not understand my comment. Or I did not understand your reply. Let me try to explain again.

To make things work I have to do C before A before B. If I understand the flow-principle I will have multiple functions which read:

r=C():
if A(r) == failure {
   handleError();
B();

Maybe even with some flow specific stuff inbetween.
How do I ensure across a team or across myself over time (future-me might no longer know what current-me knows) that we always do C before A before B?

I could introduce a functional abstraction: A function that does the above, which I call in every flow. Problem solved.

But I have broken other flow-principles. The error handler is now further away from the context that it aims to report. I no longer have the freedom to move flow specific stuff inbetween those calls to A or B.

If it is already a well known fact to everyone on the team that of course you have to C(); A(); B(); then I might just live with the risk and call that an idiom that I might even put in some documentation or specific coding guideline somewhere.

2. Maintain constant complexity by isolating it within each flow while the system grows

> I am not sure I understand: Does it mean all the statements in flow should be on the same level of abstraction, e.g. the problem domain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should not need any
other part of the system (hopefully) to deliver the feature it is designed for.

What would I see in a function which does need other parts of the system?

I find it hard to distinguish good from bad functions by that criteria.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants