Talks

Little Snippets

Little Snippets

by Xavier Noria

In this talk titled "Little Snippets" delivered by Xavier Noria at Ruby Day 2016, the speaker explores the nuanced relationship between code conciseness, readability, and personal programming preferences. Noria reflects on the subjective nature of programming decisions, where individual backgrounds, experiences, and intuitions influence choices regarding coding style and structure.

Key points discussed in the talk include:
- Personal Experience: Noria shares fond memories of Florence and his love for programming, establishing a personal connection.
- Subjectivity in Programming: He emphasizes that coding discussions often stem from personal preferences rather than objective truths, advocating for acknowledging the subjectivity in opinions expressed during coding debates.
- Conciseness vs. Readability: The speaker differentiates between concise code and readable code, arguing that while brevity is often desirable, clarity should not be sacrificed.
- Examples of Code Practices:
- Hash Literals: Noria uses the inclusion of commas in hash literals to explain how preferences can vary among developers.
- Direct Commands: He illustrates clarity improvements with examples like using 'max' instead of sorting followed by retrieving the last item to express intent more clearly.
- Active Record Queries: The pitfalls of misconstruing SQL terms in Active Record and the importance of using the right APIs for clearer code are highlighted.
- Regular Expressions: He warns against unnecessary complexities with regex and suggests using clearer predicates to improve performance and clarity.
- Documentation: Noria stresses the value of documenting code to communicate the 'why' behind implementations, aiding in smoother transitions for future developers.
- Community and Consistency: He concludes by emphasizing the significance of empathy and consistency in coding practices within communities to foster better understanding and collaboration among developers.

Overall, Noria encourages developers to reflect critically on their coding choices, acknowledging that while personal preference plays a role, the ultimate goal should be clear, efficient, and maintainable code.

00:00:09.690 All right, so first of all, thank you for having me here. This is my second time in Florence, and this city holds a special meaning for me because the first time I visited was with my wife during our honeymoon. That picture has been with us for 14 years, as we were here in 2002. It was an amazing honeymoon where we traveled on a motorbike from Barcelona to the south of France, then to Florence, and Pisa. It was a super nice honeymoon. Yesterday, I spent my day sightseeing and wandering through the center of the city. If you haven’t had the opportunity to visit this place, I highly encourage you to do so. It is impressive, not only for the art but also for the stories behind it.
00:01:00.000 Yesterday, while walking around, I reminisced about the wonderful memories from the surroundings of the Cathedral, and I feel very happy to be here. Now, as many of you know, I have been programming for a while and have read quite a bit of source code throughout my work as a consultant and in open source contributions. With time, we develop preferences and intuitions about what makes good software. Sometimes these intuitions pertain to high-level aspects, such as organization or APIs, while at other times they focus on small details of programming languages. This talk will be about those little things that sometimes make a difference. There will be opinions shared in this discussion, and I want to preface this by stating that explaining why we prefer something is not the same as proving that it is the best option.
00:01:59.200 Often when we discuss, we approach things as if we are in a logical framework prescribing that since A, B, and C hold, then we should do this, or that this option is the best for our discussion. However, that is often not the case because life is not an axiomatic system. What you're usually doing is bringing your own background, trade-offs, and preferences into the conversation. Consequently, it’s natural for you to prefer one option over another, but the problem is that your brain functions differently from that of others. You each have unique trade-offs and preferences. Thus, reaching common ground can be challenging.
00:03:29.650 I will illustrate this point with an example using code, as what I stated applies to various contexts. For example, consider a code snippet featuring a hash literal—some people might feel tension over whether to include a comma or not. In one version of the hash, a comma follows every line, while in another version, the last line does not have a comma. Is one option better than the other? It ultimately depends on individual preferences. People who prefer the version with commas value symmetry and find it helps relax their minds, as it simplifies adding new items to the hash. Meanwhile, those who favor the version without commas feel that it highlights a missing element and that keeping the hash concise is more beneficial. There’s no correct answer here; it varies from person to person.
00:04:29.050 When you write your own code, you naturally follow your preferences. However, when working in a team, discussions are necessary to reach agreements. For many aspects of programming, the specifics might not significantly affect the outcome. When we engage in discussions, it’s essential to acknowledge the subjectivity in what is being said. So, when expressing opinions, it helps to contextualize them by saying things like, 'In my opinion,' 'From my experience,' or 'In my view.' This can provide valuable perspective throughout the discussion. Additionally, I want to stress that this entire talk will be personal and based on my perspective. I'll endeavor to communicate my thoughts clearly.
00:05:58.730 I also want to enable a 'speculation mode.' At times, I may speculate about why certain things are done, and this is completely acceptable. Now, let’s start by discussing concise code. Conciseness generally refers to using few words and avoiding unnecessary information. In programming, defining conciseness in constructs is essential. Please note that all code snippets we will review in this talk are real examples extracted from open source code or actual projects.
00:07:32.500 For instance, consider a function where we have a collection being sorted to take the last item. This makes one think a bit too hard—the intention is not immediately clear. It would be much more concise and clearer if we used a direct command like 'max' to express our intent. By using 'max,' we communicate directly to the reader what the code is supposed to accomplish, significantly improving clarity. Generally, conciseness translates into choosing the most specific API available for the desired expression. Often conciseness tends to result in less code and clearer communication. There are certainly cases where I have to qualify my statements, as not every situation is 100% black and white. However, applying Occam's razor in programming means looking at a few levels of concern.
00:08:50.000 You want to express precisely what you intend through your code. Consider two scenarios: the reader looking at your code should ideally not have to think too much about what you mean when they read it. The library you're using should also have the most specialized implementation for the problem you’re trying to solve. This usually grants better performance. For example, sorting and then taking the last item is computationally expensive compared to directly taking the maximum. The benefits relating to conciseness in such cases are significant—it shortens code, improves performance, and enhances communication.
00:11:06.310 Let’s explore another example. Suppose we have an API to retrieve keys from some options object. One version of the code builds an array, while a more concise API call can retrieve the keys directly. This can sometimes lead to confusion, as someone may need to sift through the logic to recognize the operation taking place over multiple lines. A much clearer version would use an API method that communicates the intention explicitly. If you see a piece of code requiring some parsing to understand fully, it detracts from clarity.
00:13:02.640 There’s a common mistake I see often in Rails applications, where the code diverges from its intended purpose. For instance, when using ActiveRecord, one might write a query that feels more natural in SQL, using terms like 'Select' and 'Where.' However, this practice can lead to confusion, especially when one assumes an ActiveRecord method works similarly to its SQL counterpart. When one uses the correct ActiveRecord API, the code becomes clearer and doesn't leave any room for misinterpretation.
00:14:49.290 Consider another common error I often witness: people working with strings without realizing that a variable of type string does not necessarily need interpolation. If there’s a string already, using interpolation or additional method calls can lead to unnecessary redundancy. When someone uses 's' or 'p' to do something equivalent, it introduces confusion rather than clarity. Furthermore, if you’re using symbols, there are suitable practices to ensure that the code remains clean. Often, calling 'send' is appropriate when using symbols, but 'send' can also accept strings, leading to a more readable option.
00:16:44.480 Next, let’s talk about checking platform constants and regex. It's important to understand that building regular expressions can introduce unintended side effects! Some approaches involve additional steps, which may hinder performance. Consider using a predicate pattern that directly checks for matches rather than manipulating strings through multiple definitions. This results in more straightforward logic for the reader of the code.
00:18:02.020 Additionally, a common pattern among programmers is including side effects within regex operations. However, using predicates shines in performance because they do not produce side effects. Let's say we want to determine whether a string includes a substring; the inclusion check is performed with better fluency. It's also interesting to note that while we perceive clarity differently, many times we need to balance conciseness with readability.
00:19:47.280 Let's also reflect on the topic of concise versus readable code. Sometimes, we find ourselves in tension between these two aspects. For example, when initializing a structure in Ruby, be cautious with any conditional checks. It’s common to find code that makes variable assignments that parallel or conflict with the expectations of most readers. The way you organize this can significantly aid in code accuracy, enhancing flow and making it easier for a new developer or maintainer to navigate your logic.
00:21:22.500 Let’s consider when we might wish to define constants or instance variables explicitly, particularly with Ruby’s syntactical structure. It’s vital to avoid seizing generally accepted patterns blindly when developing sophisticated systems; that said, ensure you validate your associations and dependencies. If you have an ActiveRecord call that involves relationships, establishing clear dependencies prevents orphaned records from accumulating and keeps relational data accurate.
00:23:02.170 As we cover performance considerations, I challenge you to think critically about your logging strategies. Using constants for logging outputs can create risk; opting instead for global variables enhances robustness in scenarios such as testing. Sticking to global variables can streamline communication within your test suites, enabling you to capture functionality without an elaborate workaround.
00:24:41.510 When establishing your tests, ensure that regular expressions are used accurately. Regular expressions often come with implicit complexities that lead to confusion if not managed appropriately. For instance, when validating strings for specific criteria, knowing the exact purpose of character class notations and anchors—such as using '^' vs. ''—becomes crucial. Misjudging this often results in logic that does not function as intended, especially when constructing critical operations.
00:26:19.550 Similarly, the nuances around the dollar sign versus a lowercase 'end' can introduce complications, like allowing unexpected behavior in string evaluations. If the final string injects trailing newlines, the logic could break, leading to unwanted outcomes.
00:27:59.320 To summarize, we’ve explored various challenges: concise versus readable code equally warrants attention, as do the particulars that help maintain precision in expression. Be mindful that pragmatism, clarity, and fluency in syntax are vital when coding, as they shape the experiences other developers will face when reading your implementations.
00:29:32.800 Finally, I underscored the importance of documentation in codebases. Writing code is one aspect, but explaining its 'why' is equally critical. If someone inherits your code, clear documentation ensures smoother transitions and avoids perpetuating confusion. Think about the longevity of your contributions; they should resonate positively with all future interactions.
00:31:12.950 In conclusion, I would like to stress empathy in our craft. How we relate to one another, the code we review, and how we write—these all showcase our understanding of the audience, as we code together. Maintaining consistency within projects holds value; communities benefit when we strive to have styles that promote coherence. The Ruby community and others, like Go, harmonize visual patterns with audience-focused syntax!
00:32:45.460 Thank you for your attention. Now, I’m open to any questions.
00:33:57.280 Regarding the hash literals syntax query, I prefer the newer syntax for my own code, but I also respect the styles used in projects. It's about creating a comfortable environment to write in, and I can adapt to project standards without issue. Also, when defining attributes with methods, order is important. If a macro allows declaration in one line or multiple, the same clarity principles apply.