Live data from Hacker News

Clean Code vs. A Philosophy Of Software Design

github.com

541–550 of 554 posts

Re: Clean Code vs. A Philosophy Of Software Design

#541
post #132

Earlier quoted context omitted.

> "It's not object oriented programming" is only a good case to make if you think object oriented programming is synonomous with good. I don't think that's true. It's sometimes good, often not good. See, this is the sort of lazy ignorance that adds nothing of value to the discussion, and just reads as spiteful adhominems. Domain models are fundamentally an object-oriented programming concept. You model the business d…

> Domain models are fundamentally an object-oriented programming concept. They are not. > You model the business domain with classes, meaning you specify in them the behavior that reflects your business domain. I have better tools for doing that. > In Domain-Driven design, with its basis on OO, you implement these operations at the class level, because your classes model the business domain and implement business rul…

> I have better tools for doing that.

For example?

Re: Clean Code vs. A Philosophy Of Software Design

#542

Earlier quoted context omitted.

> it's not object-oriented programming. That's it. Yes, exactly. And this "classical" object-oriented programming is an anti-pattern itself . (That being said, OOP is not well defined. And, for example, I have nothing against putting related data structures and functionality into the same namespace. But that's not what OOP means to him here)

I'll reply here with a very quick example why the anemic domain model is superior in general, no matter if you do OOP or anything else. You used the example of an "order" yourself, so I'll built upon it. I would never combine functionality to update an order with the data and structure of the an order. The reason is simple: the business constraints don't always live inside the order . Here's an example why such an ap…

> I would never combine functionality to update an order with the data and structure of the an order. The reason is simple: the business constraints don't always live inside the order.

> Here's an example why such an approach inevitably must fail: if the business says that orders can only be made until 10000 items have been ordered in a month, then you cannot model that constraint inside of the order class. You must move it outside - to the entity that knows about all the orders in the system. That would be the OrderRepository or however you want to call it.

It's not that hard.

If the constraint of your example is a domain constraint, and so it's *always* valid, then when you hydrate an Order entity, other than the Order data itself, you also need to provide the total number of orders.

```

// orders is the repository, and it hydrates the entity with the total number of orders for this month

order = orders.new()

// Apply the check

order.canBeCreated()

```

Where the `canBeCreated` method is as simple as:

```

if this.ordersInAMonth > TOTAL_NUMBER_OF_ORDER_IN_A_MONTH ...

```

Fixed.

It's the same as using the OrdersRepository to query the number of orders directly before creating one, but here, the logic is just in the class.

Now, your example is pretty stupid, so I know it must not be taken literally but...

PS: I'm all but not a DDD advocate.

Re: Clean Code vs. A Philosophy Of Software Design

#543
post #315

Earlier quoted context omitted.

Is this a common usage?

I had never heard it and assumed it was gacha terminology, with SSR devs as the top 1-2% and SR devs top 20%.

Me too. Made me pine for a shiny SSR+ dev with the upgraded skin.

Re: Clean Code vs. A Philosophy Of Software Design

#544
post #37

I've enjoyed both books but Uncle Bob is something you grow out of. He was a bit of a cult figure at the time. Trying to actually follow the guidelines in Clean Code taught me a lot about "over-decomposition" and, ultimately, how not to write code. It reminds me it's possible to take aesthetics so far the results become ugly. Fussing over a proliferation of small functions that do only one thing is a kind of madness.…

> If you want to write good code, read good code. As a junior in the field working at a small company, I often rely on this community for guidance, and this seems the most sound advice on this thread.

Just a point here, "good code" is sometimes subjective, and depends on understanding the context of what the code is doing. What you think is good code might be overly verbose to another person, or overly terse, or have poorly named variables, or not have sufficiently conservative guard clauses, or throw insufficiently-granular exceptions. What you think is confusing code might lack context for where it is in the stack and what problems it needs to solve at that layer of the stack.

You can also read critical reviews of someone else's work, compare them with the work in question, and see if the critic's punches land or if they look like misses.

https://qntm.org/clean

^ This, I thought, was a good takedown of Clean Code, highlighting some cases where Bob Martin made too many overly thin functions that lacked meat and made it hard for the reader to gain context for what the function was trying to do. [1]

I would also say, reading "the same code" in different programming languages might get you a feel for if you prefer code to be more verbose or more terse, more explicit or more implicit. e.g. https://rosettacode.org/wiki/Globally_replace_text_in_severa...

[1] sometimes derisively referred to as "lasagna code" or "baklava code" -- https://www.johndcook.com/blog/2009/07/27/baklav-code/

Re: Clean Code vs. A Philosophy Of Software Design

#545
This prime generating code has fascinated me for a while.

It was first described by E.W. Dijkstra "Notes on Structured Programming (EWD249), 2nd; 1970; TH Eindhoven". https://www.cs.utexas.edu/~EWD/ewd02xx/EWD249.PDF

And then reformulated by D.E. Knuth "Literate Programming; 1984" http://www.literateprogramming.com/knuthweb.pdf

Both use it to demonstrate their way of deriving and documenting an algorithm.

And then R. Martin used it again in his book "Clean Code; 2008". (Though I'm not 100% certain what he wants to demonstrate with his rather difficult formulation.)

For the sake of this email I am going to call it "Dijkstra's algorithm".

If we look at it from an engineering perspective, then Dijkstra's algorithm is never the best choice (at least not in 2025).

If performance is not the most important aspect, e.g. if we need less than 100000 primes, then the straightforward trial division is just as fast - and soooo much simpler (basically impossible to get wrong). Note that this is different in 2025 than it was in 1970, back then multiplications and divisions were much more expensive so it made sense to minimize them.

If performance is the most important aspect, then the sieve of Eratosthenes is much faster. And you can implement the sieve with a sliding window, which is just as fast (or even a bit faster because of caching) and uses a bounded amount of memory.

Concretely - my implementation of the sliding window sieve of Eratosthenes is about 50 times faster than Dijkstra's algorithm (on the same machine) when generating the first 200 million primes (7.5 sec vs 6 min).

The reformulation - both by Ousterhout and Martin - computes multiples for every new prime found. This will quickly lead to overflow, e.g. the 6543-th prime is 65537, so its square will overflow 32 bit unsigned integers. Dijkstra's formulation on the other hand only computes multiples that are actually used to filter, the multiples are never (much) larger than the candidate.

Note that computing the multiples so eagerly will also make the multiples vector unnecessarily large (wasting memory).

Knuth and Dijkstra both remark that there is a subtle problem with the correctness of the algorithm. When incrementing lastMultiple and then later accessing primes[lastMultiple] und multiples[lastMultiple] it is not obvious that those will already be assigned. In fact they will be, but it is very difficult to prove that. It is a consequence of the fact that for every integer n there is always a prime between n and n*n, which follows from Betrand's theorem, a difficult number-theoretical result.

So if you look at Ousterhout's and Martin's reformulation and think "a yes - now I get the algorithm", then beware: You've missed at least two aspects that are relevant for the algorithm's correctness. ;-)

Re: Clean Code vs. A Philosophy Of Software Design

#546

Earlier quoted context omitted.

I'll reply here with a very quick example why the anemic domain model is superior in general, no matter if you do OOP or anything else. You used the example of an "order" yourself, so I'll built upon it. I would never combine functionality to update an order with the data and structure of the an order. The reason is simple: the business constraints don't always live inside the order . Here's an example why such an ap…

> I would never combine functionality to update an order with the data and structure of the an order. The reason is simple: the business constraints don't always live inside the order. > Here's an example why such an approach inevitably must fail: if the business says that orders can only be made until 10000 items have been ordered in a month, then you cannot model that constraint inside of the order class. You must…

I would say that this code is not good (or to be more diplomatic: not optimal). Firstly, because between `order = orders.new()` and `order.canBeCreated()`, it's possible to insert other calls or actions on or with that order, which should actually not be allowed/possible.

And second, because my original critics still holds: you now have some kind of order-entity-unrelated information inside the order (or inside its `canBeCreated()`). This will force you to touch the order-entity when removing a business constrain that is unrelated to the (single) order-entity. Because otherwise, where does "ordersInAMonth" come from? It must be able to talk to the database or something.

> Now, your example is pretty stupid, so I know it must not be taken literally but...

No no, you absolutely can take it literal. It might not be very realistic, but that doesn't change the fact that we can use it to discuss pros and cons of different designs.

> It's the same as using the OrdersRepository to query the number of orders directly before creating one, but here, the logic is just in the class.

As with my two issues that I mentioned above, the problem is the "just" in your sentence. It appears that your assessment is that the code living in a different place is merely a problem of the code being in a different place with no effect on productivity. But to me, having the code in a "wrong" place becomes a really big problem over time, especially in a big code base.

Also, we can extend this example. Let's say we have two or more entities. Like orders, users and stores and there are constraints that span and impact the state and/or creation of all of them at the same time.

Now let's compare the different approaches of us. In my case, it's rather easy: there must be some "system" or "service" the lives above all the entities that are constrained by a business rule. So if there is a business rule that touches entities A, B and C, then there must be some "system" or "service" that knows about all A, B and C and can control each of them. In other words, there cannot be a "system" or "service" that controls just A anymore. The logic to ensure the constraint then lives in that service.

With your approach, how and where do you put the code for that constraint?

And let's, just for the sake of the argument, assume that you cannot push the constraint into the database. Because that basically would be such an uber-service as described by me above. In reality, we might employ the database to (also) enforce constraints. But for the sake of the discussion, let's say we use a database where we cannot.

Looking forward to your response!

Re: Clean Code vs. A Philosophy Of Software Design

#547
post #132

Earlier quoted context omitted.

> Domain models are fundamentally an object-oriented programming concept. They are not. > You model the business domain with classes, meaning you specify in them the behavior that reflects your business domain. I have better tools for doing that. > In Domain-Driven design, with its basis on OO, you implement these operations at the class level, because your classes model the business domain and implement business rul…

> I have better tools for doing that. For example?

I would assume he meant to use the typesystem of his PL.

Re: Clean Code vs. A Philosophy Of Software Design

#549

Earlier quoted context omitted.

Force it on people, you'll see how much it works. Getting another pair of eyes on the code that you wrote is useful, but it's not free (effort, tolerance) and it's not for everyone. Just do proper code reviews. Middle ground.

> Getting another pair of eyes on the code that you wrote is useful, but it's not free (effort, tolerance) and it's not for everyone. Yeah, but to be fair I would argue that in the limit, real code reviews end up looking a lot like pair programming, and you can avoid a bunch of back and forth by both people being present during development. Obviously you still need code review (for regulatory reasons in a lot of case…

> and you can avoid a bunch of back and forth by both people being present during development.

I don't like pair programming for personal and cultural reasons (eg: I am uncomfortable with the _process_, but not the results), but the people in the pro-pair-programming camp will say the quoted bit above is one of its strengths. You back/forth and fix or change things early in the process.

Doing a code review is "too late", since these early decisions that could have been made differently/better effect all the code that follows it into a further less-optimal space.

Re: Clean Code vs. A Philosophy Of Software Design

#550
post #294

It still blows my mind how dogmatic some people can be about things like this. I don't understand why anyone takes these things as gospel. Who else has had to deal with idiots who froth at the mouth when you exceed an 80 line character margin? And it's not just programming styles, patterns and idioms. It's arguably even worse when it comes to tech stacks and solution architecture. It's super-frustrating when I'm deal…

Yes, Uncle Bob is certainly capable of being pedantic. A friend of mine, a Smalltalk Consultant, partnered with him for a while. "With Uncle Bob, it's his way or the highway." His clean code work is certainly pretty dogmatic. As I recall, he says that Java is not object oriented. But if my memory serves me correctly, his book about C++ (Designing Object-Oriented C++ Applications Using the Booch Method) has some excel…

Ah, yes. The famous Sudoku solver controversy.

In 2006 Ron Jeffries wrote four blogs about solving Sudoku in Ruby with TDD. His blogging effort ended before he completed the solution. I think he got interested in something else and left the whole thing hanging.

That same year Peter Norvig wrote a Sudoku solver in Python using a constraint based approach. You can see their respective documents here. https://ronjeffries.com/categories/sudoku/… https://norvig.com/sudoku.html

The anti-TDD lobby, at the time, hailed the two documents as proof that TDD didn't work. Ha Ha, Nya Nya Boo Boo.

I was aware of this silliness, but never bothered to study it. I had better things to do. Until March of 2020. Then I thought I'd use Sudoku as a case study for Episode 62 in http://cleancoders.com.

I had not read either of the previous documents and decided to maintain that ignorance while writing the solver in Clojure using TDD. It turned out to be a rather trivial problem to solve. You can see my solution in http://github.com/unclebob/sudoku

I don't know why Ron stopped blogging his Sudoku solver in 2006; but he picked it up again in 2024 and has written much more about it.

The trick I used to solve Sudoku with TDD was to consider the degenerate cases. Sudoku is usually a 3x3x3x3 grid. Let's call this a rank-3 problem. I started with a rank 1 problem which is trivial to solve. Then I moved on to a rank 2 problem which was relatively simple to solve; but was also very close to a general solution. After that I could solve rank N problems.

The TDD strategy of starting with the most degenerate case (rank 1) and then gradually adding complexity may not have been well known in 2006. TDD was pretty new back then. If you explore Ron's first four blogs you can see that he briefly considered rank 2 but opted to go straight into the rank 3 case. The sheer number of variables for each test (81) may have played a role in his loss of interest. In my case (rank 2) I had far fewer variables to deal with.

Post reply on HN