Should I go with Reason for my next production app?


#1

Hello everyone,

I have already posted this on reddit (in r/reactjs), but then it occurred to me that this would be even better place to ask my question(s), so I am C/P-ing it from there.

In advance I apologise for the long post, I just started typing and I haven’t realised how much did I actually write :slight_smile:

My team is about to start rewriting our current Cordova app to ReactNative. The app is B2C fitness app, with 2M+ users and after some thinking we decided that RN would be way to go. Our dev team is pretty small - there is 3 of us, we have JS background and background in OO languages such C# & Java.

We have almost no experience in React / React Native (but we have used other JS frameworks like Angular, Kendo etc.). We have had built 2 “playground apps” to test out some features, to get feeling how it is to develop in RN, to see which technologies/libraries and which project structure we will use. We decided to go with TypeScript, Redux and redux-saga (I must point our that we absolutely LOVE sagas).

But, then couple days ago I watched some React conference on YT and noticed this “thing” called ReasonML - so I dug a bit deeper and I really liked what I saw - Strongly typed, functional, immutable language which compiles to JS. Now, I must point out that I really don’t like Javascript (almost hate it, probably because of my C# background), so when I found that there is language which I can use instead of JS to write RN apps, I was: fu** yeah :D! (and other teammates are not that into JS).

So I decided to start another playground project which would fetch news from HN and display them with FlatList just to get feel of ReasonML and I really liked it.

Here are some of my thoughts / experiences after just couple of days with ReasonML
(I apologies in advance if I misunderstood smth., or I am saying smth. that is just plain stupid, as said earlier, I have almost no experience with React, and even less with ReasonML):

GOOD STUFF

  • Type safety and static code analysis are awesome and language is really expressive
  • Type safety with ReasonML is on whole another level from TypeScript (and Flow) - it is like that with TS you describe / suggest that some value is of some type, but in ReasonML that value actually is of that type)
  • Less external dependencies: In order to make JS less painful and more maintainable I had to install TypeScript, TSLint, and Prettier - in ReasonML you get all of this immediately
  • There is ReasonReact - which makes React components first class citizens of ReasonML
  • Redux is baked into ReasonReact - each component can have state, actions and reducers (just like in redux)
  • It is easy to include ReasonML outputted JS into existing JS code
  • ReasonML has some pretty nice things such as generics, variants, modules etc.
  • You can call JS functions from ReasonML, even write pure JS inside Reason files
  • Even though that “primary mode” of variables is immutable, you can mutate them if needed

PROBLEMATIC / BAD STUFF

(at least for me, with my limited knowledge of ReasonML and most of these are because ReasonML is, if I am not mistaken, around 2 years old)

  • Community, even though really really great (you get answers on Discord like immediately) is small
  • Which means there is scarce number of examples, best practices etc.
  • For example “Redux” in ReasonReact is great solution for managing local state of component (and children) but there is no agreement / best practice on how to manage Global state of the app, at least I am not aware of it, more info here (What's the best way to handle global state in ReasonReact?)
  • Regarding previous point some proposed solutions would be much better when new React Context API is introduced in ReactReason and when you browse Discord history, and comments around web - this was just around the corner, but then plans for introducing Context API to Reason have been “cancelled for now”
  • Regarding previous point - there is little known about future plans and what we can expect form ReasonML and ReasonReact (for example maybe they are working on smth. even better than Context API so we won’t need it in ReactReason)
  • If we want to stay in ReasonML world and call some existing JS libraries or external React components, we have to create bindings our selfs - for example if I am to use some RN in-app payment library, or some RN crash reporting / logging library I will have to write bindings by my self (because community is still young and there is small chance that someone has done this) - this can take a lot of time especially when adding more and more community made RN components like FastImage, or NativeBase etc.
  • Handling side-effects is done via callbacks which I absolutely hate and code is really ugly, there have been some talks for almost a year about brining async / await into ReasonML, but nothing yet
  • Documentation is ok, but could be much better

I know that everyone in ReasonML team and community is working really hard and I really do like it and believe it has potential to become the “next big thing” but I am not sure is it right for us at this stage.

I still cannot predict will it make us faster in the long run or slower (type safety = less bugs = more time for new features, on the other hand JS bindings will slow us down), will it make for great experience or will I pull my hair out when I step into callback hell?

We plan to have the same codebase for this project for next couple of years, so it is okay for me that first couple of months are hard, but after we get through initial troubles and pains we enjoy benefits of ReasonML (especially when community/syntax/tooling/libs become more mature and even better).

What are your thoughts and experiences with ReasonML?
Do you think my fears are unjustified and I mainly have them because of lack of knowledge and experience with Reason?
Do you think I should go for it, or choose “safer” route with JS/TypeScript?


#2

Your fears are not unjustified, especially when working within a team. I can tell you from our experience (a team of 3, so maybe not representative), that Reason accelerated our product iterations greatly. It may not seem that way in the beginning as you feel like you’re doing a lot of boilerplaty stuff (forms for example), but not having to write all those imports, not having to hunt bugs that get caught by the compiler - that makes a huge difference.

We have shifted almost all our production code to Reason and never want to go back. That includes our current project which consists of almost 10 thousand lines of Reason code when it’s done. It could be optimized here and there as we’re still figuring out the best way to handle monorepos and module splitting, but its a great and almost seamless experience for us thus far.

The bindings are an issue of course. We’re using material-ui, for which I have written auto generated bindings by now. That was the biggest one. All others we write bindings on a day-to-day basis and we’re not hindered by it, we’re still faster writing the bindings than using Typescript.

That’s just my 2 cents - a definite yes, go for it.


#3

Thank you very much for your answer it is really reassuring :slight_smile:


#4

I’ve had to make large decisions like this several times (co-founded 3 startups) so I feel like I can help here as i’ve paid the price for getting it wrong (and right).

Any company has a limited innovation budget before it causes harm to the company from lack of growth, overall cost, etc… Any time you tackle one of these new things you have to incur a learning curve which really slows things down (even though there are benefits). This can be especially troublesome win B2C companies where you really need the growth to either a) stay alive and pay the bills, or b) get your next round.

From what i’m hearing you’ll be paying for:

  • learning (more of) react/react-native
  • learning how/what state management works best for your react app
  • re-writing from your current app to react native (in either lang)
  • learning functional programming (it sounds like your team have been trained in OO)… this takes a while to wrap your head around and makes some weird code in the process
  • figuring out react component interopt in react-native (unsure if it’s as seamless as react)
  • dealing with differences (mainly data structures) with 3rd party react-native components
  • (potentially) writing lots of JS bindings/interopt code

So my gut reaction (without knowing more details) is that you should only write it in JS using vanilla React Native. It will be much faster to write, and if you are able to use TypeScript you can get a lot of the type safety you would get in Reason (albeit with a lot more work). Shipping is key.

That being said, once it’s built and in JS, you can always add in ReasonML to the ‘leaf’ nodes of your app and slowly convert them over to ReasonML. The conversion is non trivial but it’s really not a huge amount of work, especially when you can convert a ‘screen’ at a time. You can also target the areas that are the most ‘buggy’ and could use more type safety that you’re not getting with TypeScript.

IMHO, as much as I love Reason, I would say that your app would benefit more from using GraphQL instead of Reason. If it’s not too burdensome, adding GraphQL in front of your existing REST API would really really help with your state issues and make reasoning about your app much more clear. The back end implementation is fairly straight forward as you’re making REST calls in the GraphQL resolver and then stitching them together. In most situations this would only take a few days.

At the risk of droning on, here are some of my experiences with state management in React (i’ve been using it since before Flux/redux). React has taken a while to figure out how state works across an entire app. Today for most apps an ideal/pragmatic strategy is to split it into:

  • global state via react context (assuming you don’t have a ton), you can share the state plus a setter function
  • Apollo cache for remove/server data (eliminates redux for me)
  • shared local state at the root of a page/screen for data that persists for just that page, pass down parentState, setParentState to children
  • local state that is not shared/passed but is only consumed (perhaps a button has a onPress style state)

Redux is really overkill in this situation unless you have a lot of local state that’s shared either across siblings or very deep (but an additional context can work here too).

Worth noting… Reason React has a Context library that mimics the v16 API, as well as there being an async/await PPX that can be used until there is an official implementation (it seems pretty straightforward to migrate).

One thing i’ve really appreciated with Reason is how fast/safe it seems to be to refactor a codebase compared to a non typescript (or loosely strict flow codebase). To me it feels like it’s going to increase the speed at maintaining the software but IMHO it’s going to depend on how many changes + how often it’s changing that makes that a strong enough selling point.


#5

Thank you very much for your exhaustive feedback, it is really appreciated!

You do make really compelling arguments for not going with ReasonML from business side perspective, wrong decision could cost us company in the end :frowning: That’s why I am currently banging my had against the wall trying to decide to go with ReasonML or not.

Regarding async and Context API, you are taking about these libs ?


#6

Yep those are the ones! I would also recommend listening to the Reason Town podcast for an additional resource.

Also worth noting… if the re-write to React Native isn’t a time sensitive matter, you can always learn ReasonML and React Native on the side until it’s no longer a new thing to learn.

For my small company of a few people, we learned ReasonML on the weekends (because it was fun) and built a little app that would use similar things to the company app (router, pages, render server data, wrap a 3rd party lib, etc…). This has helped figure out the pros and cons more and when it comes time to jump in and start migrating from React to Reason React… it will be much easier and straight forward. We’re starting with adding new customer support screens in ReasonML (low cost to go back), and then migrate some of the more bug prone screens of the customer facing app…eventually replacing each screen until it’s 100% Reason.


#7

Thanks for all the info :slight_smile:

The time is of sensitive matter - I believe this is true for most of the companies, especially B2C ones.
But as we are fitness app we have this “seasonal thing” - there is drop in usage during autumn / winter months and then spike during January and spring / summer months. So our plan is to start working on the “new” app by the end of September and finish around April/May (so that we have new app for the summer) - which gives us ~7 months.
The app has ~50 screens, but most of them are just displaying data from server with little interactivity, the most complex parts are social side of the app (facebook-like feed with interactions such as commenting, liking, following users etc). and workout process which has most of the business logic.

Do you remember approx. how many weekends did it take for your team to learn Reason ?


#8

Ah that’s an interesting time constraint. My last startup was using Cordova + Meteor so I can feel your pain on that (though hopefully it’s better now with Android 4.3+ support lol).

For me it was about 2-3 weekend of hacking before I really got comfortable with it. The things bullet points I had to learn was:

  • language (easiest part for me since it’s like JS)
  • take the create react app (w/reason) and tweak it to make some simple components like a counter, learn how modules work
  • reason react routing (I used reroute or reason-navigation to clean up boilerplate)
  • building a CRUD todo app with local state
  • learn how to bind simple functions off window
  • learn how to bind/rewrap a library you’ll use
  • migrate that to handle server state (either fetch + parsing JSON and apollo/graphql)
  • deploy a test CRA app to the interwebs (https://reason-simple-form-example.netlify.com/)

If you haven’t seen rebolt I would definitely check that out as well (there’s also a video talk online somewhere from the author):


#9

Thank you very very much for all the input :smiley:


#10

I would definitely recommend Reason for anyone who build something serious. Especially with its seamless interop with JS and React.js as first class support.

But the learning curve is steep. And as you stated in previous post, the app is time sensitive, I think you should go with technology that you already know and focus on the main app.

For ReasonML benefits, I’ve built a fairly complex ReasonReact almost alone in less than a month.
image
After the initial release, I’ve been started with refactoring and and the experience is fantastic, I’m deleting code in multiple files with confident. So I can say that if you can afford the learning curve, ReasonML is better in the long-run. Especially for apps that requires refactoring a lot.

But ReasonML as a community is really young, you always ended up writing binding yourself in most cases. And that’s a really boring and error-prone process. You have to know the JS library really well in order to make a correct binding.

Furthermore, the core libraries and tools are changing really fast. It creates a lot of churns and keeping up-to-day to every release is sometimes becomes really tired.

Those are my rants about ReasonML in general. If you can invest in it, go ahead


#11

Thank you very much for your answer. I have seen your app and tired it a bit, it is great!
And it is really awesome of you to open source it, if we go with Reason, it definitively will be reference for us on how to do stuff with Reason :slight_smile:


#12

I built the app with this slogan: “By community, for community”. I set a very high standard for the app and I want to make it an example of real world ReasonReact app.