Clean Code Tip: Favor Method Chaining Over Nested Calls

  Рет қаралды 24,242

Zoran Horvat

Zoran Horvat

9 ай бұрын

Download the source code from Patreon: / source-code-for-88717639
For developers deeply entrenched in object-oriented programming, dealing with nested method calls is a familiar challenge. While OOP offers powerful paradigms for structuring and modeling complex systems, its traditional representation of method composition lags behind syntax and practices of function composition in functional languages. That very principle of combining functions to produce new, complex functionalities without a maze of nested calls is where the great power of functional programming lies.
Now, you might wonder, can we borrow this elegance from functional programming and apply it to such an OOP language as C#? The common interpretation of function composition in traditional object-oriented languages is to nest method calls which, though functionally correct, literally read our thoughts in reverse.
This is where the concept of method chaining comes into play. The C# programming language supports extension methods, a powerful tool, yet not always understood well. It lacks polymorphism, some might say, but polymorphism was never their goal. It is the function composition, like the one we have in any functional language, that we can attain by using extension methods rather than common, instance-level ones.
We can refactor these nested calls into a series of extension methods, where applicable. Such code is not only more readable but is effectively self-documenting. Every line, every chain, aligns beautifully with the original requirements, removing ambiguity and making maintenance a breeze.
Be it as it may, method chaining remains, offering a fresh perspective on structuring code. This video will equip you with a tool that promises a cleaner variant of your OOP code.
Thank you so much for watching! Please like, comment & share this video as it helps me a ton!! Don't forget to subscribe to my channel for more amazing videos and make sure to hit the bell icon to never miss any updates.🔥❤️
✅🔔 Become a patron ► / zoranhorvat
✅🔔 Subscribe ► / @zoran-horvat
⭐ Learn more from video courses:
Beginning Object-oriented Programming with C# ► codinghelmet.com/go/beginning...
⭐ Collections and Generics in C# ► codinghelmet.com/go/collectio...
⭐ Making Your C# Code More Object-oriented ► codinghelmet.com/go/making-yo...
#zoranhorvat
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
⭐ CONNECT WITH ME 📱👨
🌐Become a patron ► / zoranhorvat
🌐Buy me a Coffee ► ko-fi.com/zoranhorvat
🗳 Pluralsight Courses ► codinghelmet.com/go/pluralsight
📸 Udemy Courses ► codinghelmet.com/go/udemy
📸 Join me on Twitter ► / zoranh75
🌐 Read my Articles ► codinghelmet.com/articles
📸 Join me on LinkedIn ► / zoran-horvat
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
👨 About Me 👨
Hi, I’m Zoran, I have more than 20 years of experience as a software developer, architect, team lead, and more. I have been programming in C# since its inception in the early 2000s. Since 2017 I have started publishing professional video courses at Pluralsight and Udemy and by this point, there are over 100 hours of the highest-quality videos you can watch on those platforms. On my KZbin channel, you can find shorter video forms focused on clarifying practical issues in coding, design, and architecture of .NET applications.❤️
▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
⚡️RIGHT NOTICE:
The Copyright Laws of the United States recognize a “fair use” of copyrighted content. Section 107 of the U.S. Copyright Act states: “Notwithstanding the provisions of sections 106 and 106A, the fair use of a copyrighted work, including such use by reproduction in copies or phono records or by any other means specified by that section, for purposes such as criticism, comment, news reporting, teaching (including multiple copies for classroom use), scholarship, or research, is not an infringement of copyright." This video and our youtube channel, in general, may contain certain copyrighted works that were not specifically authorized to be used by the copyright holder(s), but which we believe in good faith are protected by federal law and the Fair use doctrine for one or more of the reasons noted above.
⭐For copyright or any inquiries, please contact us at zh@codinghelmet.com
#csharp #dotnet #objectorientedprogramming

Пікірлер: 72
@zoran-horvat
@zoran-horvat 9 ай бұрын
Download the source code from Patreon: www.patreon.com/posts/source-code-for-88717639 Learn more from the video course *Beginning Object-Oriented Programming with C#* ► codinghelmet.com/go/beginning-oop-with-csharp Learn from related videos: Clean Code Tip: Remove Messy Constructor Calls ► kzbin.info/www/bejne/bJiXmJqmhN2recU Remove Separate Concerns From a Class and Make It Favor SRP Again ► kzbin.info/www/bejne/a3S4aGRpbK6KnJY Avoid Returning Null From Methods - There Is a Better Way To Write Them! ► kzbin.info/www/bejne/foOvlZaDntFqe8U
@ryanander31
@ryanander31 Ай бұрын
Nested calls look like a sock turned inside out; that's great. ZH, love the format of your videos... showing how to improve working code with better design really helps demonstrate the underling benefits of employing patterns.
@rustamhajiyev
@rustamhajiyev 9 ай бұрын
I really like using extension methods, construct human readable chain of calls and make my code like a prose describing a feature :) Thank you for spreading the technique, Zoran 🥰
@49riddickful
@49riddickful 9 ай бұрын
Fantastic video, started by thinking that it's quite usual to solve things with the initial version, when you arrived at the final version I was really pleasantly suprised! Awesome!
@GiovanniCostagliola
@GiovanniCostagliola 8 ай бұрын
«Yoda Speaking» 😂. Your contents are becoming attractive not only for the design lessons distilled, you recall me a Finnish comedian. Really enjoyable your videos 🎉
@markky212
@markky212 9 ай бұрын
Best series in whole YT!
@zoran-horvat
@zoran-horvat 9 ай бұрын
Thanks!
@m5s10
@m5s10 9 ай бұрын
Great tips! It is very important to know that you spend much more time reading the code compared to writing it, so it is very important that it is readable. If you're having to have additional mental mapping to read code "backwards", it only uses up your concentration and downgrades what you write even further. Now, for the Star Wars fans, let me try to sum this video up in one sentence. Write code as if Master Yoda speaks you should not.
@aibarra11
@aibarra11 8 ай бұрын
this is was super helpful! i'm applying the technique in PHP Laravel. Good methodologies aren't bound by language
@perfumedeath6042
@perfumedeath6042 8 ай бұрын
Wow, amazing video. + your humor is sooo good. Informative and fun at the same time 😂😂 I hit the like button even before you said it. OMG
@shauas4224
@shauas4224 9 ай бұрын
Wow, I started watching this video with quite scepticism but the end result is 10x quality of the initial solution. Thanks sir
@nickbarton3191
@nickbarton3191 6 ай бұрын
I'm starting to get it. going back to look at my ball of mud to see what I can improve.
@nocturne6320
@nocturne6320 9 ай бұрын
I discovered your channel only recently, your videos are great and show some great principles, thank you and keep up the great work
@zoran-horvat
@zoran-horvat 9 ай бұрын
Thanks!
@oliverpolo1
@oliverpolo1 9 ай бұрын
That's fun. I recently did a fuzzy controller for a project of mine and attempted to do a fluent syntax. Although I'm not really used to writing this kind of code but it seemed like a fun challenge and I think it came out well!
@ivandrofly
@ivandrofly 9 ай бұрын
Thanks you :), this replies to the exact question I posted in the previous video
@zeldaire7484
@zeldaire7484 9 ай бұрын
This is so good. I've always wondered how chaining like this works, and can't wait to try and implement this in my own code.
@andreybiryulin7207
@andreybiryulin7207 9 ай бұрын
Main point is that you should just write your business method in valid C# the way you want first so that it expresses business requirement and then just implement what you’ve written
@XXnickles
@XXnickles 8 ай бұрын
This usage of extension methods is great. I try to apply it, when possible, but I always find it challenging when you need to use multiple parameters (typical in async flows with the cancellation tokens). C# partial application support is not nice (to put it is good words), hope you have some video ideas around this scenario for the future!
@MahmoudSaed98
@MahmoudSaed98 6 ай бұрын
Great video! Keep up the great work
@metalhead6604
@metalhead6604 9 ай бұрын
Great video! Keep up the great work. It is really teaching me a lot about modern design language!
@diogosilv4
@diogosilv4 9 ай бұрын
What a great demo! Thank you!
@devocracy1089
@devocracy1089 9 ай бұрын
Subscribed! I found this very insightful, thank you.
@anandshindey
@anandshindey 9 ай бұрын
Love it. Thanks for the video.
@DerEd94
@DerEd94 8 ай бұрын
Great video, thank you!
@5cover
@5cover Ай бұрын
I wonder if there are any languages that implement function calls as postfix operators, kind of like Smalltalk but without OOP. So you'd do 123.sqrt() instead of sqrt(123). Anyway, great vulgarization work as always. You explain things really well in a way that's easy to understand. Your videos turn coders into programmers.
@zoran-horvat
@zoran-horvat Ай бұрын
Actually, functional languages cater that kind of notation. F# uses pipe-forward operator |> for that purpose. Combined with currying, it becomes a truly powerful concept.
@user-tk2jy8xr8b
@user-tk2jy8xr8b 8 ай бұрын
Looks really nice! However, what if those are instance methods (non-static)? I can see two options: either make them static and pass `this` param explicitly, or use some sort of `|>`-like construction (that's the pipeline operator in F#), maybe something like `TO FeedTo(this TI value, Func f) => f(value);`, then you can chain anything without converting things into extensions, may look ugly sometimes though if you have additional args to close over, e.g.: `12.FeedTo(calc.Log).FeedTo(v => calc.Mul(v, 42)).FeedTo(calc.Sqrt)`. Plays more nicely with curried functions: `53.FeedTo(calc.Mul(42)).FeedTo(calc.Add(1))`
@zoran-horvat
@zoran-horvat 8 ай бұрын
C# has no syntactic support for partial function application. All it supports is the dot operator for a narrowed-down kind of function application. Being so, I am not too motivated to push it any further.
@user-tk2jy8xr8b
@user-tk2jy8xr8b 8 ай бұрын
@@zoran-horvat well, at least it supports first-class functions, hence currying. The currying doesn't play nice in C# with type inference, brings cumbersome types with it and is generally slower, so not the recommended practice, agreed
@martinprohn2433
@martinprohn2433 15 күн бұрын
Well thanks for the video. My personal opinion is, that I would have stopped before the introduction of "OrElse". I find the "FirstOf()" outer call clearer, because all three calls inside are on the same level. With OrElse on the other hand, the first call is outside the OrElse method call, but the other two inside OrElse. I find that ugly. But that’s probably just my opinion. For the same reason I prefer "Enumerable.Zip(a,b,…)" instead of "a.Zip(b, …)". (Usually with line breaks between the parameters.)
@g3ff01
@g3ff01 Ай бұрын
@zoran-horvat How would you approach testing the functionality in your example? Which part would you test and how? Which parts do you think is not necessary to test? Thank you in advance for your answer.
@zoran-horvat
@zoran-horvat Ай бұрын
Each individual method is a potential unit if you wish to test it. A method that uses chainable methods is also one unit. Its implementation is the detail you do not test. Every claim you wish to make about any of the methods is one test.
@g3ff01
@g3ff01 29 күн бұрын
@@zoran-horvat Thank you.
@ivandrofly
@ivandrofly 9 ай бұрын
Is there any video where you implemented the "DefaultIfEmptyDiscount" class?
@zoran-horvat
@zoran-horvat 9 ай бұрын
I think not, but that class is very simple (as any other is, in this design). It holds two IDiscounts, asks the first one and, if it returns a non-empty sequence, returns that sequence and ignores the other IDiscount. Otherwise, if the first sequence is empty, it just returns the second sequence. The implementation is very similar to how LINQ DefaultIfEmpty is implemented - hence the name.
@ivandrofly
@ivandrofly 9 ай бұрын
Something like this? return _other.GetDiscountAmounts(price, context).Any() ? _other.GetDiscountAmounts(price, context) : _alternative.GetDiscountAmounts(price, context); @@zoran-horvat
@kantagara
@kantagara 8 ай бұрын
Prelepo!
@parlor3115
@parlor3115 9 ай бұрын
Or if you're an FP dev, you can use the .Pipe() call, pass the arguments, all the methods you need in the pipeline and run it. It's the cleanest approach IMCO.
@pyce.
@pyce. 3 ай бұрын
Why would you prefer extension methods instead of methods on an abstract base?
@zoran-horvat
@zoran-horvat 3 ай бұрын
They are not the same thing. An extension method applies to a type but does not change it. I generally prefer functional extensions because I can organize them in per-domain namespaces, which is not the case when changing the base type whenever any domain that depends on it changes. You can view that design practice as a reinforcement of the SRP.
@antonsimkin
@antonsimkin 9 ай бұрын
Isnt it the same as Fluid Interface? What are cons of such technique? When not to use it?
@zoran-horvat
@zoran-horvat 9 ай бұрын
It becomes difficult when you need to vary the implementation. It would be a virtual method or a dependency interface in a common class, but with functions, we are back at nested calls.
@nathanel1313
@nathanel1313 8 ай бұрын
Do you see any reasonable limit to method chaining? I mean, when I get to 15 method-chains I start to second-guess myself...
@zoran-horvat
@zoran-horvat 8 ай бұрын
When there are many calls involved, then some of them naturally form meaningful groups that deserve a name and a method of their own. Having more than a couple of calls in a row already begins to look suspicious. Think of it as a SQL query with SELECT, FROM and WHERE. Consider a LINQ expression with the sequence, a call to Where, possibly Select, and then followed by a reduction operator. Anything else, with all its complexity, can be a function passed as the argument, reducing complexity by a large margin.
@Hewtoob
@Hewtoob 9 ай бұрын
I wish C# just used a void return as returning the instance that the call was made from. Then builder methods would've been a lot easier to make and not need extension methods in a separate class.
@zoran-horvat
@zoran-horvat 9 ай бұрын
Sounds interesting, but I think C# is built on more explicit rules.
@Hewtoob
@Hewtoob 9 ай бұрын
@@zoran-horvat I'm hoping something like this will come to a future C#. Maybe using 'this' as a return keyword. e.g. public this WithName(string name) { ... }.
@adambickford8720
@adambickford8720 8 ай бұрын
That sounds suspiciously like FP
@minhhieugma
@minhhieugma 9 ай бұрын
my problem with the expression is that it is hard for debugging. Let's say something wrong in the GetDiscounts, I don't know how to investigate the issue. At that time, I have to rewrite the code and create some variables to separate each call
@zoran-horvat
@zoran-horvat 9 ай бұрын
Modern debuggers are helping reduce that problem a lot. How would you debug nested calls otherwise, if not through the process you just mentioned?
@minhhieugma
@minhhieugma 9 ай бұрын
@@zoran-horvat I meant your video is great, I definitely try to write as you do in the video. I just say that I try to avoid expressions, nested functions, etc. in general because it's hard to debug. I just use them if the code is extremely clear and I would never need to investigate it in the future. I just don't want to see the whole source code with expressions and everytime I need to check something, I need to stop the debugger, rewrite the code to expose some variables and start the debugger again
@VoldHooker
@VoldHooker 9 ай бұрын
@@minhhieugma I agree. Also, ideally, code is written once, but read multiple times. I will happily give up brevity to get clarity. It also saves me from having to answer the Junior devs question about what the code does. I do not think writing terse code should be the goal. Clear code is better.
@ansh51
@ansh51 8 ай бұрын
Extension methods are great but mocking static methods for unit testing may not be ideal. Another way to do this is to just use a regular class that is not static and return the object itself on every method call. Which is what is typically used when creating Fluent APIs.
@zoran-horvat
@zoran-horvat 8 ай бұрын
Extension methods are like any other static methods. If a caller needs varying behavior, it would ask for a Func delegate, rather than depend on an extension method. Therefore, extension methods are no obstacle to testing.
@doc8527
@doc8527 8 ай бұрын
Method chaining is pretty much requiring you to implement your helper functions into a OOP way. I guess for general simple cases without thinking about OOP or adding unnecessary abstractions. The easiest way is just to break your nested calls into multiple lines. Easy to read and work for both fp and oop. ``` a = methodA(); b = methodB(a); c = methodC(b); ``` But once you realized that you will have quite amount of continuous operations upon a value. Method chaining is your good friend. Just don't abuse it everywhere.
@maurosampietro9900
@maurosampietro9900 9 ай бұрын
I was like please don’t resolve to extensions methods please please. I mean I love them and use them all the time but this was presented as a architectural problem … syntactic sugar might not be a solution
@protox4
@protox4 8 ай бұрын
This is why C# should add the pipe operator |>
@fsharpfan
@fsharpfan 3 ай бұрын
I believe that |> operator will not be added, because it would require too many changes in C#. In F# |> is a function which relies on higher-order functions.
@fsharpfan
@fsharpfan 3 ай бұрын
Why did I write higher-order function? I meant partial application, of course. I believe that implementing partial function application in C# would be very difficult.
@protox4
@protox4 3 ай бұрын
@@fsharpfan Pipe operator could easily be done in c# by lowering it to use locals. There just doesn't seem to be enough desire for it.
@stefanotorelli3688
@stefanotorelli3688 8 ай бұрын
CoR! It's hell for the common needs! You delegate but you will never know what the last step will do! That's evil!
@zoran-horvat
@zoran-horvat 8 ай бұрын
I am struggling to understand your train of thought. What is the point with knowing what the last step will do? You don't know what the immediate next step will do for the same reasons, and I don't see you calling **that** evil. My view of CoR (and any other indirection for that matter) is that it will do what its interface commands, as in the Design by Contract, to put it formally. If there is any gap in logic there, then the definition of the interface is incomplete.
@stefanotorelli3688
@stefanotorelli3688 8 ай бұрын
@zoran-horvat when I need to debug them... it will work... nope.. if I need to debug nothing is working
@zoran-horvat
@zoran-horvat 8 ай бұрын
@@stefanotorelli3688 I believe you should reconsider your programming method from the ground up. It is very difficult to try to persuade you against practices that were abandoned by the end of 1990s.
@stefanotorelli3688
@stefanotorelli3688 8 ай бұрын
@@zoran-horvat Patterns have to be used when needed. If you use them but after 2 years u left the company and nobody is going to understand what you did... who pay that? My programmming methods? lol My phylosophy: use the patterns when needed. Otherwise do not use them. Sorry if for you it's 90's but your approach is 90's more than me. And I will unsuscribe fro your channell. lol.
@ivandrofly
@ivandrofly 8 ай бұрын
The implementation done here is Yoda speaking style :D en.wikipedia.org/wiki/Specification_pattern#C#
@kis.stupid
@kis.stupid 9 ай бұрын
Nah, rather orchestrate / compose. Chaining is messy, try taking those apart. Unless you mean having one orchestrating function that invokes methods in order. Whatever you name it, as long as you don't go multiple levels deep by nested chaining
@zoran-horvat
@zoran-horvat 9 ай бұрын
I thought it was already taken apart in the previous video. Do you have any details of the design you would rather see?
@kis.stupid
@kis.stupid 9 ай бұрын
​@@zoran-horvatI edited my comment, we might be talking about the same thing. What I understand as chaining is, having a public function, call a private function which call another private function multiple levels deep. And never return. Basically voids invoking eachother in a nested manner I rather have one public function call a private function and have that return if needed, then call the next private function. So you limit to two levels deep. Otherwise it would just be nesting in disguise. I should check your prev video.
@kis.stupid
@kis.stupid 9 ай бұрын
​@@zoran-horvat I mean, a method should only do one thing, the thing it's declaring. Unless it's an orchestrator function which you'll recognize, ... Will orchestrate the invocation of multiple methods in order. What I understand in method chaining is nesting but with functions.
Keep an Eye on SRP - That Might Just Save Your Broken Code Base
22:19
Indian sharing by Secret Vlog #shorts
00:13
Secret Vlog
Рет қаралды 51 МЛН
КАХА и Джин 2
00:36
К-Media
Рет қаралды 4 МЛН
Как быстро замутить ЭлектроСамокат
00:59
ЖЕЛЕЗНЫЙ КОРОЛЬ
Рет қаралды 8 МЛН
Tame the Power of the Iterator Pattern and yield return in C#
11:36
17 Pieces of C# Syntax That Make Your Code Short
12:41
Zoran Horvat
Рет қаралды 17 М.
Master the Design of Functional Types in C#
17:53
Zoran Horvat
Рет қаралды 11 М.
Method chaining in Pandas
18:17
Python and Pandas with Reuven Lerner
Рет қаралды 1,6 М.
How to Avoid Null Reference Exceptions: Optional Objects in C#
18:13
Let Design by Contract Be Your Highest-Valued Design Method
13:40
"Stop Using Properties in C#, Just Use Fields" | Code Cop #013
11:53
"Clean" Code, Horrible Performance
22:41
Molly Rocket
Рет қаралды 845 М.
5 Design Patterns That Are ACTUALLY Used By Developers
9:27
Alex Hyett
Рет қаралды 171 М.
Выложил СВОЙ АЙФОН НА АВИТО #shorts
0:42
Дмитрий Левандовский
Рет қаралды 1,2 МЛН
Топ-3 суперкрутых ПК из CompShop
1:00
CompShop Shorts
Рет қаралды 261 М.
Xiaomi Note 13 Pro по безумной цене в России
0:43
Простые Технологии
Рет қаралды 1,9 МЛН
How much charging is in your phone right now? 📱➡️ 🔋VS 🪫
0:11