3 Shocking Misconceptions Among C# Programmers

Поділитися
Вставка
  • Опубліковано 7 чер 2024
  • Become a sponsor and gain access to additional resources ► / zoranhorvat
    Join Discord server with topics on C# ► codinghelmet.com/go/discord
    Enroll course Beginning Object-Oriented Programming with C# ► codinghelmet.com/go/beginning...
    The C# programming language and its accompanying .NET have attained many features since their inception. Some of those are confusing even the seasoned programmers, sometimes to the point that they refuse to use a specific feature years after it was added to the language.
    In this video, we will touch on three such features: record types, LINQ, and immutable design. All three are indispensable in modern design, and yet, not a small number of programmers actively refuse to use them.
    Watch this video to learn about some common misconceptions related to these three topics and how to use them as intended.
    ✅🔔 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...
    ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
    ⭐ 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 UA-cam 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 UA-cam 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.
    #csharp #dotnet #functionalprogramming
  • Наука та технологія

КОМЕНТАРІ • 106

  • @zoran-horvat
    @zoran-horvat  5 місяців тому +5

    Enroll course *Beginning Object-Oriented Programming with C#* ► codinghelmet.com/go/beginning-oop-with-csharp
    Become a sponsor and gain access to additional resources ► www.patreon.com/zoranhorvat
    Join Discord server with topics on C# ► discord.gg/SFu7pSGq

  • @dcuccia
    @dcuccia 2 місяці тому +2

    Love this presentation style - Zoran, you are the C# Socrates gadfly that we needed. :)

  • @obinnaokafor6252
    @obinnaokafor6252 5 місяців тому +3

    Another amazing lesson. Thank you.

  • @fremler6695
    @fremler6695 5 місяців тому +3

    I'm new to the bad practice(?) to use collections as part a record. I've tried to read up on it, but I don't quite understand. Is it as easy as I shouldn't use a record if I need my type to hold a list?
    As always, great video and content!

  • @Nojo524
    @Nojo524 5 місяців тому +2

    I wish C# can have the pipe operator like that of F#. I don’t think that can be possible based on how it is designed. That would be a game changer.

  • @modestas3d391
    @modestas3d391 Місяць тому +1

    Excellent insights. Though I would disagree a bit with "Everyone must learn programming before doing programming". Sometimes the best way of learning things is just making a an attempt to build something without diving too deep into theory. Even though you know it will be garbage in the end.
    Thanks for sharing and keep it up with the great content!

  • @RiversJ
    @RiversJ 5 місяців тому +2

    Linq isn't slow anymore, but it still isn't where it would need to be for applications that need to squeeze hard.
    The people who have reason to care take more issue with the very easy to lake allocations when the code is required to hit at most a few kb per sec at most, preferably none.
    Any discussion in a specific project is worthless if you don't profile and know how to do it right.

  • @_IGORzysko
    @_IGORzysko 5 місяців тому +6

    Hi Zoran, great video! Could you elaborate a little bit on why collections should be avoided to be put in records?

    • @zoran-horvat
      @zoran-horvat  5 місяців тому +7

      Because record implements GetHashCode and Equals and collections don't. There are two ways to compare two collections: in order or out of order. Since the collection cannot decide which one is right, it cannot implement Equals.

    • @qorxmazmaharram8300
      @qorxmazmaharram8300 5 місяців тому

      ​@@zoran-horvatregular c# classes also implements default these methods

    • @LCTesla
      @LCTesla 5 місяців тому

      @@zoran-horvat so the solution is to use a collection type that does unambiguously implement GetHashCode? what are the (best) candidates?

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      @@qorxmazmaharram8300 They do but it is not appropriate for value-typed semantics. Two identical records would say they differ if they contained collections, even if collections have the same content.

    • @phillipsma
      @phillipsma 5 місяців тому

      @@zoran-horvat what if the collection was an implementation wrapper around immutablelist that also did a sequence compare. A ValueCollection if you like. I've implemented this myself for a document hierarchy that i needed to check for changes, including order of elements in some sub property collection.

  • @deltaphilip8611
    @deltaphilip8611 5 місяців тому

    I am still using c# 7.3 because I cannot figure out how to update my compiler in VS.

  • @spechulfapticks3108
    @spechulfapticks3108 5 місяців тому

    7:52 Is it slow? No, when it is done right ©
    that's actually the reason of choosing the right design for the thing, you are implementing. i think, people tend to classify the immutable design as "slow" because they just don't have the application for it in their day-to-day work

  • @metallixbrother
    @metallixbrother 5 місяців тому

    Regarding DTOs; should we make them mutable as suggested in your example? And I understand that having a collection in a record messes up value equality, but then what should we do instead?

    • @zoran-horvat
      @zoran-horvat  5 місяців тому +1

      The purpose of a DTO is to transfer data. It is not a model, and immutability plays no role in its design.
      Regarding the question about collections, they violate the value typed semantics, and hence the containing class should not implement GetHashCode and Equals methods. It can be a common immutable class.

  • @quantume7143
    @quantume7143 5 місяців тому +1

    Great video :)

  • @websystema
    @websystema 25 днів тому +1

    Thank you

  • @VincentYang024
    @VincentYang024 3 місяці тому

    Not fully get it why record will not contain an id? Can you please explain a bit further? Thanks

    • @zoran-horvat
      @zoran-horvat  3 місяці тому

      ID implies mutation. It is not a problem to have it in the record per se, but be prepared to turn it into a full-blown class (and remove equivalence members!) if it turns out that you will have to mutate the object.
      For example, I implement quite a few entities in my designs as records, even with EF Core, because they are insert-only. But sometimes it turns out that I must implement mutation on some of them because there comes a request to support edit, e.g. to let the user fix typos. That is how I let a record with ID evolve into a common class later.

  • @alfonsdeda8912
    @alfonsdeda8912 5 місяців тому

    Hi Zoran, when should i know that record isn't the right choice and change it to a class type?
    I mean, records are used for immutable structure and for value type equality, my question is when i need more methods to change the logic, this breaks the immutable state and should be changed to a class, I am right?

    • @Dr-Zed
      @Dr-Zed 5 місяців тому +1

      Try a functional approach where your objects stay immutable. If you need to change the state, try to create a function that returns a new immutable object.

    • @alfonsdeda8912
      @alfonsdeda8912 5 місяців тому

      @@Dr-Zed should I use class or records in that case?

    • @Dr-Zed
      @Dr-Zed 5 місяців тому

      @@alfonsdeda8912 records of course. The "with" keyword is what you'll want to look at

  • @HOSTRASOKYRA
    @HOSTRASOKYRA 5 місяців тому +8

    We all need more education )

    • @vladislavzhuravlev6440
      @vladislavzhuravlev6440 5 місяців тому

      Totally agree with you, but have called to mind this: "Hey, Teacher, leave those kids alone!"(c) ))

    • @HOSTRASOKYRA
      @HOSTRASOKYRA 5 місяців тому

      @@vladislavzhuravlev6440 We have a proverb: "Live a hundred years, learn a hundred years, and still die a fool"
      What you are doing is not teaching, it is a very cool product. )

  • @yanivrubin7202
    @yanivrubin7202 5 місяців тому +4

    The performance problem with linq is more related to the extra objects it creates on the heap. Some extra objects are created each time you call linq query.
    You can use lazy enumerable without linq and you will just save the extra object(s).
    But unless It's in an extra hot path the readability/re-use benefits outweigh the slight performance degradation.

    • @patfre
      @patfre 5 місяців тому +2

      Another reason is using the wrong method for the job

    • @davidmartensson273
      @davidmartensson273 5 місяців тому

      Most problems with linq I have seen is when you re iterate the same query multiple times, like .Count() and then a foreach on the same IEnumerable.
      Sure, if your data is small enough to not cause cache issues and contained in a ready made list a simple for loop will often be faster than a linq query, but as explained in the video, its going to be the rare case when that difference is actually measurable.
      In most cases, spending the same time to improve DB queries and looking for more ways to cache data that does not change as much will usually win you much more performance.
      So using Linq can add performance even if the specific Linq query could be made faster in it self just by the time you get to spend on other performance problems :)
      I have seen monster Linq queries that really did have huge performance costs but that was not good code by any standard unless obfuscation and one liners was the design goal.
      Just breaking them apart and simplifying usually resolved all problem while still using linq for 90 % of the original one liner linq.

  • @7th_CAV_Trooper
    @7th_CAV_Trooper 3 місяці тому

    How can you keep objects out of the Gen 1 heap?

    • @zoran-horvat
      @zoran-horvat  3 місяці тому

      What do you mean by that?

    • @7th_CAV_Trooper
      @7th_CAV_Trooper Місяць тому

      @@zoran-horvat I'm asking what makes an object "short lived" as mentioned near 7:30 in the video. Presumably this is the gen 0 heap you're talking about and the GC gets complicated for longer lived objects that move to the gen 1 heap.

  • @MegaJoka100
    @MegaJoka100 5 місяців тому +1

    In the context of DTOs and records, I'm always unsure if I should use the default record (class) or a readonly record struct. When should I choose which?

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      The decision record class vs. record struct is the same as class vs. struct. The default decision is usually record class.

  • @georgehelyar
    @georgehelyar 5 місяців тому

    I think gen 0 GC does look at short lived objects because it has to determine what is rooted in order to promote to gen 1, but still it's a micro-optimisation, and as with all optimisations, you should profile it before optimising it. Unfortunately most C# devs i know don't do either.
    The assumption that gen 0 is free and IO is expensive is a reasonable starting point when you're first writing the code though.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      There is the sweep step in between where GC does consult unreachable objects, but only as an optimization of the memory management itself, therefore making its operation overall faster.

    • @georgehelyar
      @georgehelyar 5 місяців тому +1

      "Value types are stored on the stack, reference types are stored on the heap" is the most common mistake I see when people try to optimise, when in reality it will often be used on a reference type or boxed, but they don't really understand when boxing happens

  • @VoroninPavel
    @VoroninPavel 5 місяців тому

    I'd use required and init keywords for DTOs' properties.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      That is just details. The substance is in equality comparisons.

    • @VoroninPavel
      @VoroninPavel 5 місяців тому

      ​@@zoran-horvatI agree, and that's where c# designers somewhat mixed the things. IMO primary constructor combined with property declaration is one thing, and value semantics - another one. Almost in 100% cases people use positional records for DTOs (they are extremely concise). Hardly anyone uses record instead of class and then declares properties as with old classic DTOs

  • @barionlp
    @barionlp 5 місяців тому

    Do you have a good in depth video about immutable design?

    • @zoran-horvat
      @zoran-horvat  5 місяців тому +2

      Most of the code I made in my previous videos is immutable.

    • @almostdev6580
      @almostdev6580 5 місяців тому +4

      You can also read Scott Wlaschin's great book: "Domain Modelling made functional"

  • @aivascu
    @aivascu 5 місяців тому +2

    Wow that record DTO stone landed in my backyard with a loud thud...
    Never thought about collection value equality in DTOs. Probably because I don't often have collections in DTOs.
    So, ok records are only valuable as value-object types? But value object types need to be constructed in a valid state, cause they represent a value...
    So the primary constructors on records make even less sense on a records since they don't validate anything except possible nulls which can be easily ignored with the bang (!) operator.
    Same for records with only init-only properties, while they do eliminate the clutter of backing fields they miss the opportunity o validate the data set in those properties.
    So the only other explanation for this mess is indeed catering for FP. However in that case the validity of data in those records can only be guaranteed by the correctness of the function producing them... which is quite a big ask.
    The whole immutable design done right argument is also very frustrating. Immutable design done right can indeed be powerful, but doing it wrong is so easy I'm not even sure it's worth attempting in most cases. Sure if most developers were true professionals this wouldn't be an issue, but this cannot be further from reality.
    The more I think of if the more frustrated I get

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      Validation does not belong in a record the same way it does not belong in an int or in a string.

    • @aivascu
      @aivascu 5 місяців тому

      @@zoran-horvat yes this is what I concluded above. The way records are structured, discourages any kind of guards before the arguments are accepted so they're not useful as (DDD) value objects either. The only remaining use is something like a structure in FP (eg. F# records).
      Though you can't create cartesian product of two records (yet?), they're still immutable (by default but not mandatory) meaning they can enable some FP practices, thread safety maybe.
      As of now the records are an overhyped and vastly misunderstood concept in C#, that's not really applicable to most code-bases.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      @@aivascu Is int also unusable for DDD?

    • @aivascu
      @aivascu 5 місяців тому

      @@zoran-horvat this is not what I meant. I said they don't fit the value object description.
      I'm no DDD expert by any means, but in my understanding in DDD protecting domain invariants is mandatory, and mostly done by the domain entities themselves. In my understanding this means that no invalid values are allowed to exist inside the Domain. The only use I see at the moment for records in DDD is maybe as temporary representations of values while they are being processed and before they are applied back on the domain.
      Perhaps they can be used in domain and integration services? I'm curious to know what you think.

    • @adambickford8720
      @adambickford8720 5 місяців тому +1

      @@zoran-horvat For the hardcore, yes! 'int' has no semantic value, what does it represent? So they'd ultimately wrap that int in a 'value object' like `FavoriteNumber` which would prevent things like nulls or negative values (arbitrary constraint)

  • @WESFFFFF
    @WESFFFFF 3 місяці тому

    Comparing a struct to passing PersonId, Firstname and Lastname to a method, is not a fair comparison (6:54). Passing a single class reference to a method would be faster.

    • @zoran-horvat
      @zoran-horvat  3 місяці тому

      There are no structs in that portion of code. It's all values and classes.

    • @WESFFFFF
      @WESFFFFF 3 місяці тому

      ​@@zoran-horvat oh you are right, my bad. But when you are mentioning programmers saying immutable is slow, they often mean struct coping is slow. Not the new class records.

  • @georgehelyar
    @georgehelyar 5 місяців тому

    The collections on records thing annoys me.
    If I have a record with a collection of records on it, I would have liked it to keep the value equality, without having to write custom equality or custom collection types etc. It also trips people up because there is no warning that the collection is compared by reference

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      There is no definition of equality among collections: there are at least two valid, and different, equality comparisons for any two collection instances.
      I think that the issue that annoys you comes from attempting to put a collection onto a record in the first place - that is needless and cumbersome, also making it very difficult for the consumer to use. Collections simply do not belong there.

    • @georgehelyar
      @georgehelyar 5 місяців тому +1

      How would you model 1:m composition?
      My argument is that if the properties of a record are compared by value then when the properties are collections then they should also be compared by value.
      For example if a book has a title then you could use a record to represent it, but if it has a title and a set of authors then you couldn't use a record to represent a book? That doesn't make sense to me. The part that annoys me is that you need to know an implementation detail to know that it won't work.

    • @johnnykeems2911
      @johnnykeems2911 5 місяців тому

      @@georgehelyar Records are shallowly immutable, i.e.if a record has a mutable attribute such as a List, it's not automatically immutable anymore. However there are some third party implementations out there, that eventually could help with your scenario, for example ImmutableListWithValueSemantics, ValuesCollection etc

    • @1992jamo
      @1992jamo 4 місяці тому

      @@johnnykeems2911 What about an array? Is a record with a immutable property still comparable?

  • @edgeofsanitysevensix
    @edgeofsanitysevensix 5 місяців тому

    Why is it not correct to have a collection within a record?

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      Because record defines value-typed semantics and collections don't. That would break the record.

    • @edgeofsanitysevensix
      @edgeofsanitysevensix 5 місяців тому

      @@zoran-horvat If we use a record to seralise some data when passing it around, how do we consolidate a 'DTO' that might contain data allong with collections of data?

  • @allinvanguard
    @allinvanguard 5 місяців тому +4

    Your last point perfectly nails my pet peeve with a lot of development practices - The general idea that allocations of any kind are bad. According to the generational hyphotesis, either allocations are quickly discarded in gen 0 or they might last very long and are not a massive concern to the GC. If I hear someone talking about avoiding allocations for performance reasons and I know they are not a game dev or have some perf measurements to back it up, then I immediately raise my eyebrows because it's usually just a feeling and not a fact they are concerned about.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      That is exactly the point I tried to communicate in this video. Allocations alone are not the problem. They can become a problem when combined with some other factor.

  • @EugeneS88-RU
    @EugeneS88-RU 5 місяців тому

    Anyway... In some cases Linq is not the best choice. From my gamedev experience: Need to avoid using linq in methods wich called every tick - it's so expensive for GC (memory allocation+defragmentation) -> decrease performance. Hello Unity3d and Linq in Update()

    • @zoran-horvat
      @zoran-horvat  5 місяців тому +2

      Agree, but game development is very specific.

  • @LogicException
    @LogicException 5 місяців тому

    With regard to point two, I think the statement "LINQ is slow" is a bad one. What is slow? Where does it start and where does it end?
    Is LINQ slower (!) than if you don't use it? Yes, of course. LINQ is just candy for the developer to be able to write many lines in a few short ones. Does this sugar cost time? Yes. Does it make it slower? Yes. Is the resulting readable code more important than performance in many cases? Probably, but not always.
    Whether LINQ is slow cannot be answered and is not answered in the video. It depends on too many factors, which are individual for each case.
    The video also only presents one case. It would have been better if the video had gone into more detail and raised awareness of what LINQ means and what the advantages and disadvantages are. So you do exactly the same bullshit as the "LINQ is slow" community: you found the "LINQ is not slow" community. What nonsense.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      "LINQ is slow" is a misconception.

  • @fritzfahrmann4730
    @fritzfahrmann4730 3 місяці тому

    yes, linq is not slow, but code written by hand can be faster and avoids this garbage
    greate video like always :)

    • @zoran-horvat
      @zoran-horvat  3 місяці тому +1

      What garbage?

    • @fritzfahrmann4730
      @fritzfahrmann4730 3 місяці тому

      @@zoran-horvat don't remember which linq methods were affected ... the bad classics would be .ToList and .ToArray
      but for most/nearly all people Linq is great

    • @fritzfahrmann4730
      @fritzfahrmann4730 3 місяці тому

      @@zoran-horvat 4:25 "create an object ... and leave it to the GC"

    • @zoran-horvat
      @zoran-horvat  3 місяці тому

      @@fritzfahrmann4730 ToList and ToArray are not actually LINQ. Those are helper methods, literally shortcuts to calling the List's constructor and Array.Copy.
      Proper LINQ methods differ in no way from foreach, both in terms of performance and the amount of objects they produce while operating. You cannot beat LINQ by writing the loops manually.

    • @zoran-horvat
      @zoran-horvat  3 місяці тому

      @@fritzfahrmann4730 Same thing in foreach, literally. How else would you work with objects if you don't create them, and what else can you do after you're done with them but leave them to the garbage collector?

  • @adambickford8720
    @adambickford8720 5 місяців тому

    Remember, it only has to be *effectively* immutable, which may not require copying. A substring might just refer to the same object with different offsets vs copying. If you are really nervous, look into 'persistent structs' (nothing to do with databases).
    If you don't have metrics and SLAs, stfu about performance.

  • @jorgeromero4680
    @jorgeromero4680 5 місяців тому

    I like your videos but these times at 5:20 are a joke! A real web request would never be so fast across the world, not even in Europe is so fast. Particularly this code would be slow as hell if needs to retrieve one result from a DB and yield it across the world! A better strategy would be some kind of pagination.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      The times assume a fairly small response (which is a reasonable assumption). The consequence is that TTFB and TTLB can be considered equal.
      The times I have used in the calculation are optimistic, because my goal is to estimate the worst case for the value under investigation.
      I am not sure what you find funny in that process, since it is following regular engineering practices, namely to estimate the upper bound for a measure of interest.
      BTW, the estimates I have calculated are ignoring the possibility of distributing the servers geographically. The "time across the world" and "time within Europe" can be surprisingly and arbitrarily short. For example, I am measuring round-trip time to google.com consistently under 10ms, which makes response transfer time below 5ms.

    • @jorgeromero4680
      @jorgeromero4680 5 місяців тому

      @@zoran-horvat I appreciate your detailed explanation regarding the timing estimates and assumptions made in the video. While I understand your approach in considering a small response size for the calculation, real-world scenarios often involve larger data sets or varied network conditions that might impact performance differently. The optimistic estimations, while helpful to visualize best-case scenarios, might not always align with practical experiences, especially when dealing with diverse geographic locations and varying database loads. Geographical distribution of servers can indeed improve response times significantly, as you've pointed out with Google's impressive metrics. However, in scenarios involving database queries and transmitting data across distant locations, considering the potential latency and actual response times becomes crucial. Pagination or other optimization strategies might indeed be more advisable in scenarios where database operations and global data transmission are involved to manage the potential slowdowns due to network latency and larger data payloads.

  • @kocot.
    @kocot. 5 місяців тому +3

    very clickbaity, records are not DTOs, linq has its place, immutables have their place -> if none of this shocks you, keep scrolling... I wish creators with respect to viewers used clearer titles

    • @zoran-horvat
      @zoran-horvat  5 місяців тому +11

      You are so lucky to live in the world in which programmers around you don't come around every day just to say that records are DTOs and nothing more, that LINQ is slow and useless and that immutable design is crap.
      You could have read all that in comments on my other videos, but you did not bother to.
      You could even visit my channel to see that I don't do click baits, but you didn't bother to.
      Still, you couldn't resist but to post.

    • @kocot.
      @kocot. 3 місяці тому +1

      ​@@zoran-horvatcome on, '3 shocking misconceptions' is as much of a clickbait as it can be - a title that tells little about the content, while makes you want to open it just to see if you know what the 'shocking' things those are. And well, none of those are shocking.
      The fact your channel has people agreeing with you doesn't mean that a) most of your viewers do -> most will just ignore b) those that stick with this channel are representative -> it's actually the opposite, those that stick to your channel are a filtered group of people thinking alike (the big, SHOCKING, mystery of social media/you tube/profile target bubbles)

    • @zoran-horvat
      @zoran-horvat  3 місяці тому

      @@kocot. You have so many misconceptions about so many people.

    • @kocot.
      @kocot. 3 місяці тому

      @@zoran-horvat lol

  •  5 місяців тому

    The worst video from Zoran I've ever seen. I need more education to understand it.

    • @zoran-horvat
      @zoran-horvat  5 місяців тому

      Is it the worst video, or do you need more education? You need to make a choice first.

  • @anarhistul7257
    @anarhistul7257 5 місяців тому

    Records are bad DTOs