Hacker News new | past | comments | ask | show | jobs | submit login

If you make all your code as pure function, then testing is easy.

First thing to do: Stop using class. Ask yourself first: Should i use a class here and there ?

Wait, i miss something here: Writing pure functions is hard ?




Alright, so you get numbers from a json file in a ftp servers, you use scipy.newton to perform root finding on it, but needs the number of steps to be outputted as well (which newton() doesn't return), and you will save the result in a postgres table.

All this should be send to a task queue, triggered by a call to your REST API.

Good luck with purity.


"Railway Oriented Programming"[1] is a (functional) technique to achieve purity despite steps that could result in error states. The error states are hidden/pushed to the very edges/end of your code. So you can focus on the "happy state" for the main business logic:

> Many examples in functional programming assume that you are always on the “happy path”. But to create a robust real world application you must deal with validation, logging, network and service errors, and other annoyances.

> So, how do you handle all this in a clean functional way?

> This talk will provide a brief introduction to this topic, using a fun and easy-to-understand railway analogy.

Functional programming keywords/shorthands: option/either/monads

[1]: https://fsharpforfunandprofit.com/rop/


> Good luck with purity.

Most of your counter example needs integration tests to test properly anyhow - not really a good point.

If you can give up encapsulation (which IMO isn't actually that useful in practice) and in return, your program becomes 95% functional, that seems like a really good tradeoff.


1. code that listens to a REST API and puts a request on a task queue

2. code that listens to the task queue for new jobs

3. code that fetches a file from the FTP server

4. code that converts the JSON file to a format appropriate for the root finding

5. code that performs the root finding

6. code that converts the result of (3) to a format appropriate for insertion into a table

7. code that inserts the result into a Postgres table

Steps 4, 5 and 6 seem easy enough to implement in a pure fashion.


Yeah, just reading their description I was like "the middle part seems easily done as its own thing".

"Functional Core, Imperative Shell" was just posted too, this is the perfect example of where that structure works: https://news.ycombinator.com/item?id=34860164


You’re describing a bad API to begin with. Those are too many steps to test at once too.


What's your definition of "pure function". Apparently not "pure function" in the sense of "pure functional programming", because if that were so, your claim would just be wrong. Counterexample: "printToConsole: IO[null]": is a pure function but still not easy to test.


The definition of "pure function" I'm familiar with from functional programming has no side effects including I/O. Assuming 'printToConsole' is performing I/O, you're describing a impure function.


Then you have not understand what (pure) functional programming is and how it works.

I recommend you to have a look at Haskell, probably the most famous language for enforcing only pure functions in your program. And I took this example from Haskell.

Here is a good starting point for this concrete example: > https://stackoverflow.com/questions/59035420/understanding-p...

Quote (from the course 'Haskell Fundamentals Part 1' mentioned in the post):

> This example helps illustrate that putStrLn is not a function with side effects.

The answers explain the concept quite well.


While there is an important sense in which even IO values in Haskell are still pure values, it is not helpful in the case of testing.

    $ ghci
    GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
    Prelude> putStrLn "hello" == putStrLn "hello"
    
    <interactive>:1:1: error:
        • No instance for (Eq (IO ())) arising from a use of ‘==’
        • In the expression: putStrLn "hello" == putStrLn "hello"
          In an equation for ‘it’: it = putStrLn "hello" == putStrLn "hello"
If you want to test your IO code, and you should, you still have to test them from the perspective of them actually executing in the real world. There's no way to test them as pure values. The snippet above is only the beginning of your problems if you wanted to do that, but it a plenty sufficient problem on its own. In addition to the obvious problem that it points out that IO values are already not comparable to each other in the naive sense, there's also the more philosophical problem that the IO values are your programs, so even if you could run the test I show above, on more complicated expressions, your tests would be asserting that you wrote the program you thought you wrote, not that the program you wrote does what you think it should do.


I agree, that was my point.

You probably replied to the wrong person.


Writing pure functions isn't necessarily hard.

However, solving a business problem with only pure functions is indeed hard




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: