Type Driven Domain Modelling, Part 2: Evolving Models with F#
lucasmreis.github.io
lucasmreis.github.io
I know a lot of people don't want to hear this but these types of languages, functional first, are the future of our industry. (In the sense that in the 2000s Java like laguanges were the future of our industry). I might be reaching here, but in my opinion, these are the right languages for the Cloud and that's why they are getting so popular.
However, for complex representational systems, including both transactional and continuous systems in business, commerce and industry, other languages and paradigms can remain better suited.
Hello. Respectfully, what is a complex representational system? Why are other languages/paradigms better suited over a language like F#?
A database is one example.
A database is also global mutable state for the programs that write to it, and that significantly compromises the advantages of using functional programming languages for such programs. You might start with some nice pure functional code, but the database adds massive side effects.
It is entirely the opposite. PFP exposes the murky aspects of mutability, provides abstractions around it, and ensures that you're not tripping over yourself in regards to mutability.
Back in the days they were mandatory since memory was expensive and you simply had to access stuff from disk and needed something that made it reasonably efficient. Now memory is so cheap and for quite many business applications it would be feasible to keep everything in memory. SSDs with GB/s level read speeds would enable restoring the stuff back to memory in reasonable time in case the cluster goes down.
I think the whole database thing also caused major issues on the object oriented side and actually stopped people from really using OO (or getting benefits out of it). Instead of building intelligent and smart objects it is easy to end up with objects that are just containers for data.
Probably there has been thoughts on how to do this, one old project I remember is Prevayler[1].
SQL and ORM are a superb fit for a great many applications, incidentally a large share of real world applications. The four-letter abbrev. CRUD comes to mind, as well as reporting.
Most kinds of NoSQL remove some benefits of the relational model while not really giving you the benefits of object persistence. I never felt a great need to use it; since quite some of these databases also had all sorts of issues that not exactly endeared trust for serious applications -- I'm not working on software where that's an OK thing to have (though for others it might be an acceptable tradeoff).
The real deal persistent object databases are a completely different beast from both NoSQL and relational models (only some NoSQL concepts like explicit / application-level indexing carry over). Two important things to note about these: 1.) There are not many of them 2.) Properly using them already requires proper OO technique. Failing 2.) will make it an unmaintainable mess. Certain kinds of applications benefit greatly from these, and there they also tend to perform better in both developer experience and efficiency as well as application performance than forcing a huge impedance mismatch down the throat of an ORM -- which pretty much always means that the underlying relational DB is used in very anti-patternish ways, resulting in poor performance regardless how good the DB actually is.
My feeling is that in traditional business apps you don't have so much needs to these random searches over huge amount of data. It's more about taking hold of one piece of the graph and then navigating to related objects (dummy example: search for customer, then start looking at that customers orders).
I'm not familiar with Smalltalk, but I'm sure there was some ideas related to persistence other than just ORM and relational database (but could be those ideas have been proven as bad over the years). I just find it a bit strange that we have been building these things pretty much the same way for the last 20+ years. Meanwhile the hardware has changed much. Even with quite small corporate hw budget you are looking at half a terabyte of RAM and tens of cores in a single server.
It's the basis of most Zope apps, including Plone, but also many other applications; there's not much talk about it, because it just works. Like in the comment I made below; if it's a good fit ze ZODB is quite literally worth every LoC in gold.
The database itself doesn't do that much (apart from giving you transparent object/application persistence, transactions and MVCC :), as one would expect.
The Zope people made an excellent job of modularising it (or, in other words: this is by principle extremely modular), so there are a bunch of packages commonly used around it (eg. BTrees, zodburi, often either ZEO or RelStorage and stuff like eg. zope.container).
(Historically it's also very interesting - development started in 1997! The revision history is an interesting read, too, many familiar names pop up, including GvR)
1. Representational systems
a. Transactional systems [1], based around actions that need to be recorded, typically for commercial or legal reasons, like software used to record your purchases, payments, reservations, participation, interactions, obligations, results, commitments, plans, and significant events.
b. Non-transactional continuous systems, like software controlling an elevator, warehouse conveyor system, or a vehicle engine management system.
As such it is more of a Type 2B project - "Information, data science and analysis projects, systems often focused on the processing of data." (http://aryehoffman.com/entry/project-types)
Anyway, I asked you about a blockchain technology because it fits perfectly into your description of a representational technology. In fact it's a breakthrough in the space, and I'm finding it hard to believe that an IT professional doesn't have even a basic idea about about it.
We'll hear about these more and more for sure.
Companies like Facebook aren't what the majority of us works on.
So when selling languages to management "look Facebook does it" usually doesn't help at all, what one needs are how that adoption will help those IT costs go down.
I can see a lot of value for that in non-tech companies that correctness is crucial, like finance, insurance, health...
Also share your opinion, and go even further, for me personally IT projects should be accountable just like in many industries.
However my experience in enterprise consulting, with applications written in Excel, or languages that allow for "replaceable programmers", is that business doesn't care if software is the same quality of 1 € shop items, as long it generates the desired output.
Always goes that way.
As language geek I dabble in every language I can put my hands on.
Yet when it comes to work, it is always Java, C#, JavaScript, C++, SQL, because that is what RFPs allow for.
It's already happening with Elm, Elixir, etc.
There are zero jobs for Elm, Elixir, .... where I live.
I am asserting "most of us never will never be allowed to use them at work.", which is quite different point.
Not everyone can relocate just for the pleasure of using another programming language.
But I guess not having job offers on the region one lives is not considered making a point.
Oops, did you read that as imperative? It was just meant to be present tense. I didn't mean that you were recommending people not use these languages, just saying jobs aren't presently available in most companies. I missed the ambiguity when I wrote it; my bad.
My point was that the fact that you are not currently being allowed to use these languages doesn't imply that new languages won't be added to the list of "Java, C#, JavaScript, C++, SQL" - there was a time when none of those were on the list. It may be that there is something in particular that will prevent the addition of "these languages" but it hasn't been spoken to.
Mainstream languages will incorporate functional features and remain popular, and they will not be superseded by pure functional languages. Java and C# are already doing this.
* mutable by default
* OO by default
* null by default
* structural equality a pain to implement
* immutable types a pain to implement
* verbose syntax / failing at the DRY principle
* statement based rather than expression based
* large codebase following those idioms
I don't think they'll not remain popular, but I think a more important share of people will eventually "get it" that there are alternative approaches which are sound, same or greater potential to achieve and thriving eco-system.
If you want to sell a language to the upper layers, you need a list of business reasons, not language features.
As for me, I also use the awareness of manager to the developer needs to be productive, give best ROI and would definitely use that to select a job.
Really reduced codebase size and features like type provider which increase safety and saves from writing boiler plate code do save on the bottom line, especially in maintenance.
Also, if you are using vanilla C# for math computation, you can save CPU/energy by translating it to F#, it tends to run significantly faster, that also impacts the bottom line in some contexts.
There are ways a C# aficionado would take to try to not be so verbose, but those solutions won't be considered idiomatic by 99% of C# developers.
At the end of the day, codebase size matters a lot.
I do not think we're going in this direction, necessarily.
In the meantime, you probably need slightly, but not massively, better developers.
Lots of stuff that is easier to do. Not much that is harder.
Like I said to OP F# doesn't have that "hard sell", it's just a bunch of incremental improvements that end up being a big deal together, but each one on it's own is unimpressive.
I would say HM type inference is a non-incremental "hard sell" improvement, but it depends on the target audience :).
I'm currently learning a couple of LISP variants (Closure and LFE). With ClojureScript, Elm, PureScript, BuckleScript, and even plain ole ES6, functional on the frontend is more compelling than ever.
So, if we only want to call a couple of animations and submit a form, I agree that a small script with three jQuery-style functions can do the job.
But that's rarely the case nowadays, in my experience. Almost every frontend project I came across professionally became a full application at some point.
There's the need of dealing with concurrent user interactions, online data requests to the server, non-traditional form behaviors, different routes...
http://banashek.com/posts/20170204-a-brief-peek-at-universal...
Sharing types, validators, etc mean that the api communication is type-safe.
Otherwise, great article. This is exactly how I learned to program with Scheme: mosel the domain carefully, slowly building up helper functions, and conposing at the end.
And, as some commenter on Disqus said, probably the right thing to do would be returning an Qty option from the function, and treating it properly.
I have no experience with Scheme, but already worked with Clojure - it was actually my "gateway" to functional programming languages, hehe!
Then using a bit of F# Quotations, I can convert most match queries to XPath queries and query SQL Server directly (still work-in-progress).
But running into performance problems, so it's not 100% done.
http://stackoverflow.com/questions/41949177/f-data-types-sql...
(defstruct product nil
sku
price)
(defstruct event nil)
(defstruct add-to-basket event
product
quantity)
(defstruct line nil
product-sku
quantity
line-total)
(defstruct basket nil
lines
total
(:postinit (me)
(set me.total [reduce-left + me.lines 0 (usl line-total)])))
(defvarl empty-basket (new basket))
(defun build-line (product quantity)
(new line
product-sku product.sku
quantity quantity
line-total (* quantity product.price)))
(defmeth basket add-to (me product quantity)
(flet ((transform-line (line)
(if (equal line.product-sku product.sku)
(build-line product (+ line.quantity quantity))
line)))
(let* ((transformed-lines [mapcar transform-line me.lines])
(product-already-in-basket (nequal transformed-lines me.lines)))
(if product-already-in-basket
(new basket lines transformed-lines)
(new basket lines (cons (build-line product quantity) me.lines))))))
(defmeth basket update (me event)
event.(add-to me))
(defmeth add-to-basket add-to (me basket)
basket.(add-to me.product me.quantity))
REPL: $ txr -i typemodel.tl
1> (new add-to-basket product (new product sku 42 price 5) quantity 4)
#S(add-to-basket product #S(product sku 42 price 5) quantity 4)
2> (new basket)
#S(basket lines nil total 0)
3> *1.(add-to *2)
#S(basket lines (#S(line product-sku 42 quantity 4 line-total 20)) total 20)
(The silly implementation of the product-already-in-basket is a literal transliteration of the original.)If you see me designing programs like this in real life, just whack me on the head, please!
(defmeth basket add-to (me product quantity)
(labels ((insert (lines)
(tree-case lines
((line . rest) (if (equal line.product-sku product.sku)
(cons (build-line product
(+ line.quantity quantity))
rest)
(cons line (insert rest))))
(() (list (build-line product quantity))))))
(new basket lines (insert me.lines))))