News for hackers. Stuff that matters.
Re:Why I hate all articles about design patterns (2016) by nathanaldensr on Monday March 05, 2018 @02:11AM (#16519333)
Of all the patterns you could pick on, you pick on one of the most useful in modern OOP; however, I think you actually intend on picking on dependency inversion, not injection. Dependency injection is simply an automated way to satisfy constructor dependencies in OOP languages where your intent is to invert a dependency graph. I won't go into why dependency inversion (see: Dependency Inversion Principle, the "D" in SOLID) is so valuable because much has already been written on the topic.

As far as your email example, sometimes the language's basic type system abstractions (e.g., string, integer, etc.) do not encapsulate a real-world concept sufficiently. Encapsulation failures can frequently lead to bugs when edge cases are hit. I may, indeed, need to create an Address class to replace "string address" parameters if there is validation logic inherent to the existence of an email address in my code. If there isn't, then the base type of string would do just fine, of course.

Re:Why I hate all articles about design patterns (2016) by crimsonalucard on Monday March 05, 2018 @03:41AM (#16519655)
>Of all the patterns you could pick on, you pick on one of the most useful in modern OOP; however, I think you actually intend on picking on dependency inversion, not injection. Dependency injection is simply an automated way to satisfy constructor dependencies in OOP languages where your intent is to invert a dependency graph. I won't go into why dependency inversion (see: Dependency Inversion Principle, the "D" in SOLID) is so valuable because much has already been written on the topic.

Both patterns are total failures. You are talking about the most misguided religiously followed pattern(s) in all of modern programming. AN equal amount has been written about how horrible both DI concepts are if you care to look. You think putting an acronym in your response and using big words like injection proves a point? Not SOLID at all. It proves nothing.

You have literally ignored my main point. It baffles me how blind some people are. The Email object requires 10x more code and 10x more abstractions and 10x more unit test coverage to finish then a singular function. You haven't even addressed this fact yet.

>As far as your email example, sometimes the language's basic type system abstractions (e.g., string, integer, etc.) do not encapsulate a real-world concept sufficiently. Encapsulation failures can frequently lead to bugs when edge cases are hit. I may, indeed, need to create an Address class to replace "string address" parameters if there is validation logic inherent to the existence of an email address in my code. If there isn't, then the base type of string would do just fine, of course.

Do you seriously think that encapsulating an email address in an object makes a difference? Here's some "validation logic" for you:

    //raises error if invalid
    validate_email_address(email: str)
I cannot make an example more clear. If you want to send a VALID email all you need is a function that validates an email and a function that sends it. You do not need to shove validation into an extra object then inject it into another one, then instantiate that object then call the send method... Doing this adds NOTHING beneficial to your code.

This one guy told me that by encapsulating the email address into an Address object I am effectively eliminating a runtime exception from the system because the type checker is, in a way, doing the validation. haha. I cannot comprehend how this guy cannot visualize the fact that all he is doing by using an address object rather then a validation function he is just creating a class then basically moving the validation function over to be a method of that class. The runtime error can still occur... just in a different location and obscured by useless abstractions and code surrounding it.

Many OOP patterns are pointless abstractions. Many smart people hate OOP all together, (including the founder of YC and this site). Maybe you should look into why.

You are basically the topic of this article.

Re:Why I hate all articles about design patterns (2016) by tuukkah on Monday March 05, 2018 @04:26AM (#16519810)
The runtime error can still occur... just in a different location and obscured by useless abstractions and code surrounding it.

One point of a type such as EmailAddress is that the validation is invoked at one place (inside the constructor) as opposed to an invocation at every usage site like send_email, which is a lot of work and error prone.

Another point is that when validation fails you get the runtime exception with a useful stack trace: instead of "address X was not valid when trying to send email" you actually get "you tried to convert string X to email address but it's not valid". In the first case all you can do is fail to send the message, but in the second case you can ask the user again, fix your escaping code etc.

Re:Why I hate all articles about design patterns (2016) by watwut on Monday March 05, 2018 @03:59AM (#16519698)
> 10x more unit test coverage to finish then a singular function.

That is not true. Assuming that both have same functionality, e.g. both either validate address correctness or both don't, you need exactly same test cases. The only difference is that they will be structured differently - in one case you validate address as part of `AddressObject` test and in another as part of `func email` or `func validate_email_address`.

The tests with valid and invalid address however needs to exist in both cases.

Whether you go by functional or object oriented way, validation should be separated from main. It can be in another object or in another function, but it definitely does not belong to main function that does also sending. There is very little difference between two, the only one is that whether you validate before hitting send function of after.

> You do not need to shove validation into an extra object then inject it into another one. Doing this adds NOTHING beneficial to your code.

It is not big deal either. It does not make it harder to understand, both variants are dead simple. Both are immediately readable. Frankly, people who have low abstract thinking or were lazy to learn basics of OOP hate it. It is the same as with people who hate any other paradigm - functional programming and what have you. Functional programming is too hard to read unless you have put work into learning it.

There is such a thing as bad OOP, but when you pick dead simple easy to read example and claim it is something complicated, the the issue is not with OOP.

Re:Why I hate all articles about design patterns (2016) by crimsonalucard on Monday March 05, 2018 @04:22AM (#16519794)
>That is not true. Assuming that both have same functionality, e.g. both either validate address correctness or both don't, you need exactly same test cases. The only difference is that they will be structured differently - in one case you validate address as part of `AddressObject` test and in another as part of `func email` or `func validate_email_address`.

Typically when you make a class. You create additional methods under that class. Those additional methods such as getters, setters, constructors, all need to be unit tested for full coverage. Like I said... Cruft code.

>Whether you go by functional or object oriented way, validation should be separated from main. It can be in another object or in another function, but it definitely does not belong to main function that does also sending. There is very little difference between two, the only one is that whether you validate before hitting send function of after.

We're in agreement here except I never brought up functional programming. Where in my post did I say it? I'm talking about procedural programming. Like C.

>It is not big deal either. It does not make it harder to understand, both variants are dead simple. Both are immediately readable. Frankly, people who have low abstract thinking or were lazy to learn basics of OOP hate it. It is the same as with people who hate any other paradigm - functional programming and what have you. Functional programming is too hard to read unless you have put work into learning it.

This is besides the point. I don't care about how hard or how simple or how lazy people are. I'm talking about pointless logic and unneeded abstractions. This is what the article is talking about. Here is a way to make it even more clear. Compare the two below:

    Class Email(AddressObject, SubjectObject, MessageObject, ConfigObject, ClientObject).send_mail(msg: str, subject: str, address: str)

    func send_mail(msg: str, subject: str, address: str)
Do you see how the send_mail method is IDENTICAL to the send_mail function? The class and the dependencies getting injected into the class are a pointless layer of abstractions when ALL you need to send an email is the send_mail method. This is the core of the argument. Don't get into semantics about people being lazy.

And also, again, I never mentioned functional programming. I'm not talking about it. I'm talking about straight up procedural programs of just regular functions that you see often in C code.

>There is such a thing as bad OOP, but when you pick dead simple easy to read example and claim it is something complicated, the the issue is not with OOP.

I picked something dead simple and easy so readers can understand what I'm talking about. You'd rather me hand you some OO source code so you can parse that insanity?

Re:Why I hate all articles about design patterns (2016) by watwut on Monday March 05, 2018 @06:01AM (#16520199)
> Typically when you make a class. You create additional methods under that class. Those additional methods such as getters, setters, constructors, all need to be unit tested for full coverage. Like I said.

That is great argument for why full coverage is nonsense. Why would you test getters, setters and constructors if they do little?

> Compare the two below

I read and understand both just fine. Moreover, second one must have a place where equivalent of config and client objects go - but I dont see where it is. Or, you added do-nothing config and client objects go to OOP example to make it look worst. OOP example also have address twice, subject twice and message twice.

Here is more equivalent code:

* Class Email(AddressObject, SubjectObject, MessageObject).send_mail()

* func send_mail(msg: str, subject: str, address: str)

> I picked something dead simple and easy so readers can understand what I'm talking about.

The trouble is, that readers dont see it.

The point of functional was analogy.

Re:Why I hate all articles about design patterns (2016) by crimsonalucard on Monday March 05, 2018 @09:56AM (#16521412)
>That is great argument for why full coverage is nonsense. Why would you test getters, setters and constructors if they do little?

Errors and code changes can happen at anytime and anywhere and in places you never look. You have full coverage for full safety.

>I read and understand both just fine. Moreover, second one must have a place where equivalent of config and client objects go - but I dont see where it is. Or, you added do-nothing config and client objects go to OOP example to make it look worst. OOP example also have address twice, subject twice and message twice.

The function doesn't need a config object or a client object because those are patterns and abstractions that are unnecessary. That is the point of the article. Patterns that are blindly followed religiously and abstractions used in a way that is excessive.

>The trouble is, that readers dont see it.

It's not possible to speak about what other people see. You can only speak to your own intelligence which is the only logical possibility here.

>The point of functional was analogy.

The point was that you think functional and oop are just two different styles of programming that are both equal and good. This is incorrect. One is better than the other but at the end of the day I wasn't even comparing those two styles.

Re:Why I hate all articles about design patterns (2016) by watwut on Monday March 05, 2018 @10:50AM (#16521809)
Which patter requires config object and client object for send mail functionality? I read a lot about them and there is none. So, unless you can name it, you are making stuff up.

It is not even about abstraction. I can write func send_mail(msg: str, subject: str, address: str, from: str, server: str, port: num, <following 20 config variables>) and have procedural code with same functionality.

Writing test for every getter and setter will not give you safety at all. This sort of test is completely pointless.

Re:Why I hate all articles about design patterns (2016) by majidazimi on Monday March 05, 2018 @04:18AM (#16519778)
I don't want to start a war. I'm neither an expert programmer nor a smart person. But isn't it better to put data and validation all together? What if someone forgets to call the validation function? I mean in some complex projects, there may be tens of those validation functions that need to called, probably in a special sequence.
Re:Why I hate all articles about design patterns (2016) by crimsonalucard on Monday March 05, 2018 @04:41AM (#16519888)
Put the validation function as part of the email function. Compose the many validation functions into a single validtion function:

    validate_email(email: str, subject: str, msg) -> bool
        return validate_msg(msg) && validate_subject(subject: str)

This makes it hard to "unit test" as hard core unit testing purists like to test the email function decoupled from other dependencies such as validation. The reality is, it's not that big of a deal to test both functions at once in a single unit test. You can't prove "unit_tests" is any better than regular "tests"

And if you really want to do DI you can always do this:

    email(address: str, subject: str, message: str, address_validator_function: func)
Though travelling in this direction we're diving deeper into another type of pattern that can be abused. Still, passing functions as parameters still leads to less cruft code then straight up passing a method that's part of an object.
Re:Why I hate all articles about design patterns (2016) by smadge on Monday March 05, 2018 @04:19AM (#16519786)
In this example, the main point is to have the type system do work for you. Some languages have bad type systems and I agree in those languages it is often more work than it's worth to write type safe code. However, in general, I would much rather have an EmailAddress type and if I am passed an EmailAddress I can be confident it is actually an email address.

For example I could have the only way to construct an email address be (in Haskell)

    makeEmailAdress : String -> Maybe EmailAddress 
With the validation logic in the constructor. This is no more complicated than your solution.

As an added benefit my type signatures are now also doubling as documentation.

Re:Why I hate all articles about design patterns (2016) by crimsonalucard on Monday March 05, 2018 @04:27AM (#16519820)
I know Haskell. We don't even need to address replacing exceptions with monads to show how and why OOP and patterns are in many many cases a bad solution.
Re:Why I hate all articles about design patterns (2016) by smadge on Tuesday March 06, 2018 @01:23PM (#16530781)
The point has nothing to do with functional vs oop, or exceptions versus monads. It has to do with using the features of your language of choices type system to prevent bugs. The thing going on here is putting validation logic in your type constructors so it's impossible to construct an invalid type without triggering a runtime "exception" or error.
Re:Why I hate all articles about design patterns (2016) by crimsonalucard on Friday March 16, 2018 @11:08AM (#16601169)
Ok I get your point. You can still have a function take in an address object rather than inserting into another object with a constructor.

You are correct in that building types leads to a more safe program but I was more addressing the flaw with objects rather then types.