3 ms·
My main project over the last few years has been a photobooth, so I've done server-side in suave (I LOVE suave compared to any other .net framework), client-sid
by daxfohl 9y ago
My main project over the last few years has been a photobooth, so I've done server-side in suave (I LOVE suave compared to any other .net framework), client-side in WPF (F# experience in WPF is meh), and a bundle of other mini projects. I did it in F# because it was interesting, not because it was more productive at the time.
My personal landing point is about #6 in the turtles article. I still like classes and interfaces and think they fit perfectly well. However, inheritance is something I avoid completely now. The effect can be done much more flexibly and transparently by several other means. But one great thing about classes is that you get nice autocomplete when you type `myservice.`. And note I only use OO for "services"; data is data is data. So if you're doing DB stuff, prefer an anemic data model and a platform that supports it (so Dapper rather than EF or NHibernate). Basically do `db.Save(myData)` rather than `myData.Save()`.
Another big change I've noticed is I don't use "private" functions much anymore. In OO I spent a lot more energy making sure that people using my classes couldn't use them wrongly. They could only do exactly what the requirements allowed. I think OO mindset (at least in C#/Java, maybe Python is different) makes you paranoid and guides you to putting "app code" into what should be "libraries". This sometimes made e.g. unit testing more of a pain; you can't test your "validate" functions directly because they're private. Now I tend to open most everything up and let developers do what they want with my code, but I add a few helper functions to cover the common cases to guide them in the right direction. In general I consider everything a library now; the only "app-specific" code I write goes in `main` function that glues everything together. Of course I still don't open functions that expose contained services, or that leave things in an inconsistent state, but that's about all.
And of course embrace immutability and recursion (or the library functions that do it for you).
Probably the most annoying thing for you, especially coming from Python, will be "similar records". So you'd need a `User` that just has raw data, `UserDb` that maybe has that plus an ID/DateAdded/DateModified, a `UserOut` that maybe has that minus PasswordHash, a `UserIn` that maybe has RawPassword/RawPasswordAgain, etc, and conversions between them all. Not to mention if you want different schemes for jsonNaming, db_naming, RecordNaming, etc. I've yet to come up with a happy typesafe way of doing this.
- vram22 9y ago> So you'd need a `User` that just has raw data, `UserDb` that maybe has that plus an ID/DateAdded/DateModified, a `UserOut` that maybe has that minus PasswordHash, a `UserIn` that maybe has RawPassword/RawPasswordAgain, etc, and conversions between them all. Why is this needed in F#? Something to do with immutability?
- daxfohl 9y agoThis assumes you want to use records for your data: records don't have inheritance. So whereas in C# you could create a UserDb that extends User with the Id/DateAdded fields, in F# that's not idiomatic. I am sure there could be a good way to automate this using type providers, but I haven't tried it yet.
- daxfohl 9y agoI created a gist of the pattern I've found to be most successful when doing an app in F#. https://gist.github.com/daxfohl/0183db108924ee87440928cb803dcfc3 https://gist.github.com/daxfohl/0183db108924ee87440928cb803d...