This post advocates for using Ruby's built-in features, specifically Struct
, to create value objects. It argues against using gems like Virtus
or hand-rolling complex classes, emphasizing simplicity and performance. The author demonstrates how Struct
provides concise syntax for defining immutable attributes, automatic equality comparisons based on attribute values, and a convenient way to represent data structures focused on holding values rather than behavior. This approach aligns with Ruby's philosophy of minimizing boilerplate and leveraging existing tools for common patterns. By using Struct
, developers can create lightweight, efficient value objects without sacrificing readability or conciseness.
Steve Losh's "Teach, Don't Tell" advocates for a more effective approach to conveying technical information, particularly in programming tutorials. Instead of simply listing steps ("telling"), he encourages explaining the why behind each action, empowering learners to adapt and solve future problems independently. This involves revealing the author's thought process, exploring alternative approaches, and highlighting potential pitfalls. By focusing on the underlying principles and rationale, tutorials become less about rote memorization and more about fostering genuine understanding and problem-solving skills.
Hacker News users generally agreed with the "teach, don't tell" philosophy for giving feedback, particularly in programming. Several commenters shared anecdotes about its effectiveness in mentoring and code reviews, highlighting the benefits of guiding someone to a solution rather than simply providing it. Some discussed the importance of patience and understanding the learner's perspective. One compelling comment pointed out the subtle difference between explaining how to do something versus why it should be done a certain way, emphasizing the latter as key to fostering true understanding. Another cautioned against taking the principle to an extreme, noting that sometimes directly telling is the most efficient approach. A few commenters also appreciated the article's emphasis on avoiding assumptions about the learner's knowledge.
Refactoring, while often beneficial, should not be undertaken without careful consideration. The blog post argues against refactoring for its own sake, emphasizing that it should be driven by a clear purpose, like improving performance, adding features, or fixing bugs. Blindly pursuing "clean code" or preemptive refactoring can introduce new bugs, create unnecessary complexity, and waste valuable time. Instead, refactoring should be a strategic tool used to address specific problems and improve the maintainability of code that is actively being worked on, not a constant, isolated activity. Essentially, refactor with a goal, not just for aesthetic reasons.
Hacker News users generally disagreed with the premise of the blog post, arguing that refactoring is crucial for maintaining code quality and developer velocity. Several commenters pointed out that the article conflates refactoring with rewriting, which are distinct activities. Others suggested the author's negative experiences stemmed from poorly executed refactors, rather than refactoring itself. The top comments highlighted the long-term benefits of refactoring, including reduced technical debt, improved readability, and easier debugging. Some users shared personal anecdotes about successful refactoring efforts, while others offered practical advice on when and how to refactor effectively. A few conceded that excessive or unnecessary refactoring can be detrimental, but emphasized that this doesn't negate the value of thoughtful refactoring.
Good software development habits prioritize clarity and maintainability. This includes writing clean, well-documented code with meaningful names and consistent formatting. Regular refactoring, testing, and the use of version control are crucial for managing complexity and ensuring code quality. Embracing a growth mindset through continuous learning and seeking feedback further strengthens these habits, enabling developers to adapt to changing requirements and improve their skills over time. Ultimately, these practices lead to more robust, easier-to-maintain software and a more efficient development process.
Hacker News users generally agreed with the article's premise regarding good software development habits. Several commenters emphasized the importance of writing clear and concise code with good documentation. One commenter highlighted the benefit of pair programming and code reviews for improving code quality and catching errors early. Another pointed out that while the habits listed were good, they needed to be contextualized based on the specific project and team. Some discussion centered around the trade-off between speed and quality, with one commenter suggesting focusing on "good enough" rather than perfection, especially in early stages. There was also some skepticism about the practicality of some advice, particularly around extensive documentation, given the time constraints faced by developers.
Summary of Comments ( 2 )
https://news.ycombinator.com/item?id=43421324
HN commenters largely criticized the article for misusing or misunderstanding the term "value object." They argued that true value objects are defined by their attributes and compared by value, not identity, using examples like
5 == 5
even if they are different instances of the integer5
. They pointed out that the author's use ofComparable
and overriding==
based on specific attributes leaned more towards a Data Transfer Object (DTO) or a record. Some questioned the practical value of the approach presented, suggesting simpler alternatives like using structs or plain Ruby objects with attribute readers. A few commenters offered different ways to implement proper value objects in Ruby, including using theValues
gem and leveraging immutable data structures.The Hacker News post titled "How to create value objects in Ruby – the idiomatic way" has generated several comments discussing various aspects of value objects in Ruby and alternative approaches.
One commenter points out that using
Struct
for value objects can be problematic when dealing with inheritance, particularly when attributes are added to subclasses. They suggest usingData.define
as a potential solution to this issue, as it creates immutable objects by default. This commenter also mentions that theComparable
module provides a more concise way to define equality and comparison methods based on the value object's attributes. They provide a code example illustrating this approach.Another commenter questions the necessity of the article's approach, suggesting that a simple class with an initialize method and attribute readers would suffice in many cases. They argue against over-engineering simple value objects, emphasizing the importance of readability and maintainability. This commenter also raises the potential for performance implications when using modules like
Comparable
, suggesting benchmarking to determine the actual impact.A different user focuses on the use of
::new
in the original article's example, explaining that it's not required and is likely a stylistic choice. They point out that using just.new
would be the more common and concise approach in Ruby.The conversation then shifts towards a discussion of the benefits and drawbacks of using
Struct
versus defining a custom class. One commenter highlights thatStruct
can be handy for quick prototyping or when the value object is extremely simple. However, they acknowledge the limitations ofStruct
, such as difficulties with inheritance and the inability to easily add custom methods. Another commenter mentions usingOpenStruct
as an alternative, but acknowledges its own set of trade-offs, particularly regarding performance.Finally, a commenter draws attention to the
dry-struct
gem from thedry-rb
ecosystem, advocating for its use in creating more robust and feature-rich value objects. They specifically mention the gem's ability to handle type coercion and validation, making it a suitable option for more complex scenarios. Another comment chimes in endorsingdry-struct
and adding that using it is generally superior to relying onStruct
. They mentiondry-struct
's ability to specify types, which aids in catching errors early.