{"id":47910,"date":"2020-09-10T11:23:50","date_gmt":"2020-09-10T18:23:50","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/xamarin\/?p=47910"},"modified":"2020-09-11T08:53:58","modified_gmt":"2020-09-11T15:53:58","slug":"fabulous-functional-app-development","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/fabulous-functional-app-development\/","title":{"rendered":"Fabulous: Functional App Development"},"content":{"rendered":"<p><em>This is a guest blog by Timoth\u00e9 Larivi\u00e8re. Timoth\u00e9 is the maintainer of <a href=\"https:\/\/github.com\/fsprojects\/Fabulous?WT.mc_id=fabulous-blog-jamont\">Fabulous<\/a> and a Microsoft MVP. You can find him on Twitter <a href=\"https:\/\/twitter.com\/Tim_Lariviere\">@Tim_Lariviere<\/a>.<\/em><\/p>\n<h2>Fabulous App Development<\/h2>\n<p>Fabulous is an open-source framework for building mobile &amp; desktop apps using functional programming (FP) with <a href=\"https:\/\/fsharp.org\/\">F#, a .NET functional-first programming language<\/a>. It is available on GitHub at <a href=\"https:\/\/github.com\/fsprojects\/Fabulous?WT.mc_id=fabulous-blog-jamont\">https:\/\/github.com\/fsprojects\/Fabulous<\/a>.<\/p>\n<p>Applications built with Fabulous use the MVU design pattern (Model-View-Update, also known from the origin <a href=\"https:\/\/guide.elm-lang.org\/architecture\/\">The Elm Architecture<\/a>). These app also use declarative views written directly in F#.<br \/>\nThis may already feel familiar to you if you have played with frameworks like React-Redux, Flutter, or SwiftUI.<\/p>\n<p>Object-oriented programming (OOP) is widely used today. However, in this post, we will elaborate on how FP can also be an awesome tool for building apps.<\/p>\n<p><em>A few apps made with Fabulous for Xamarin.Forms, from left to right: <a href=\"https:\/\/github.com\/fsprojects\/Fabulous\/tree\/master\/Fabulous.XamarinForms\/samples\/FabulousWeather?WT.mc_id=fabulous-blog-jamont\">FabulousWeather<\/a>, <a href=\"https:\/\/github.com\/TimLariviere\/FabulousContacts?WT.mc_id=fabulous-blog-jamont\">FabulousContacts<\/a> and <a href=\"https:\/\/github.com\/TimLariviere\/FabulousPlanets?WT.mc_id=fabulous-blog-jamont\">FabulousPlanets<\/a><\/em><\/p>\n<p><center>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousWeather-473x1024.png\" alt=\"Image FabulousWeather\" width=\"160\" class=\"size-large wp-image-47914\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousWeather-473x1024.png 473w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousWeather-139x300.png 139w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousWeather-768x1662.png 768w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousWeather-710x1536.png 710w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousWeather.png 828w\" sizes=\"(max-width: 473px) 100vw, 473px\" \/><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousContacts-473x1024.png\" alt=\"Image FabulousContacts\" width=\"160\" class=\"size-large wp-image-47912\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousContacts-473x1024.png 473w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousContacts-139x300.png 139w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousContacts-768x1663.png 768w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousContacts-709x1536.png 709w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousContacts.png 946w\" sizes=\"(max-width: 473px) 100vw, 473px\" \/><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/FabulousPlanets.gif\" alt=\"Image FabulousPlanets\" width=\"160\" class=\"size-full wp-image-47913\" \/>\n<\/center><\/p>\n<h2>Fundamentals of MVU<\/h2>\n<p><em>Note: We will see MVU as defined by Elm, which is the definition used by many F# libraries.<\/em><br \/>\n<em>The upcoming MAUI will integrate a different variant of it.<\/em><\/p>\n<p>Before diving in, let&#8217;s expand on what the MVU pattern is and how it differs from more traditional MVVM apps.<\/p>\n<p><center>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/MVU.png\" alt=\"Image of MVU\" width=\"754\" height=\"150\" class=\"aligncenter size-full wp-image-47915\" srcset=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/MVU.png 754w, https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/MVU-300x60.png 300w\" sizes=\"(max-width: 754px) 100vw, 754px\" \/>\n<\/center><\/p>\n<p><em>Credits: Beginning Elm (https:\/\/elmprogramming.com)<\/em><\/p>\n<p>The idea is to have a state (also called <code>Model<\/code>) that is immutable and can only be changed through messages (<code>Msg<\/code>) that are processed by the <code>update<\/code> function. Those messages are then sent when users interact with the application or when external factors happen. Such as async request completes, push notifications, and switching between dark and light modes. Each time the state is updated, Fabulous will ask for the matching UI state and will transition between them transparently.<\/p>\n<p>MVU provides several advantages over MVVM:<\/p>\n<ul>\n<li><em>Immutable state<\/em><\/li>\n<\/ul>\n<p>In MVVM, the ViewModel (which holds the state) is mutable and is usually changed in multiple methods in reaction to what happens. When the app grows bigger, make extra effort and be careful when adding new changes to not break existing behaviors unknowingly. In MVU, the immutability of the app state ensures that it won&#8217;t ever be changed outside of the dedicated <code>update<\/code> function, without a dedicated message. This makes it very simple to add new features without worrying about breaking something.<\/p>\n<ul>\n<li>\n<p><em>Centralization &amp; explicitness<\/em><br \/>\nThe structure of MVU is really simple and enforces explicitness.<br \/>\nThe state can only be initialized in the <code>init<\/code> function and changed in the <code>update<\/code> function only for declared <code>Msg<\/code>s, the UI can only be declared in the <code>view<\/code> function.<br \/>\nThis makes it really easy to welcome new developers to the codebase and makes debugging a lot easier.<br \/>\nIf it breaks, there&#8217;s only one place.<\/p>\n<\/li>\n<li>\n<p><em>No concurrency issues<\/em><br \/>\nThe user navigates, data gets loaded, animations end, &#8230; Reacting to one event is easy, but when you need to handle multiple events at the same time, it becomes tricky.<br \/>\nThis can lead to obscur errors, very hard to understand and sometimes impossible to reproduce.<br \/>\nFabulous helps you avoid this kind of problem by applying concurrent messages one after the other.<br \/>\nAlso, Fabulous lets you monitor its MVU loop so you can know what happened in which order.<br \/>\nEasy to replay that one corner case!<\/p>\n<\/li>\n<li>\n<p><em>Ease of testing<\/em><br \/>\nA best practice in FP is to write functions that only depend on their parameters and not on the global context, much like static methods.<br \/>\nThose functions are called pure and are really easy to test, for the same parameters you&#8217;ll always get the exact same output.<br \/>\nWith MVU, the <code>init<\/code>, <code>update<\/code> and <code>view<\/code> functions are pure by default. Meaning you can unit test them super easily, including your UI!<br \/>\nYou can <a href=\"https:\/\/github.com\/TimLariviere\/Fabulous\/blob\/play\/Fabulous.XamarinForms\/samples\/CounterApp\/CounterApp.Tests\/Tests.fs?WT.mc_id=fabulous-blog-jamont\">see an example here<\/a>.<\/p>\n<\/li>\n<\/ul>\n<h3>Thinking About the UI<\/h3>\n<p>Thanks to its declarative nature, Fabulous also completely changes the way we need to think about the UI.<\/p>\n<p>In MVVM, the UI is created once and bindings are listening for changes. This requires us to think carefully about the current UI state to make the necessary changes (&#8220;Is that spinner still displayed?&#8221;).<br \/>\nWith declarative views, we only need to care about the state we&#8217;re given to build the required UI. Fabulous will take care of all the necessary changes when transitioning between the current UI to the new one.<br \/>\nThis greatly reduce the burden on the developers, speeding the development process and avoiding a lot of potential issues, especially in big applications.<\/p>\n<p>Finally, the fact that the entire app state is stored in a single object makes it dead simple to serialize it on disk when the OS forces you to stop. On reboot, simply deserialize this <code>Model<\/code> and you&#8217;re immediately back where you stopped!<\/p>\n<p>Enough with abstract talk, let&#8217;s see an example.<\/p>\n<h3>The Counter App<\/h3>\n<p>We have a simple counter app. One button for incrementing, one for decrementing, and a label showing the current value.<\/p>\n<p><center>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/counter-app.gif\" alt=\"Image counter app\" width=\"200\" class=\"aligncenter size-full wp-image-47911\" \/>\n<\/center><\/p>\n<p>Here is the full code of the counter app:<\/p>\n<pre><code class=\"fs\">module Counter\n\nopen Fabulous\nopen Fabulous.XamarinForms\nopen Xamarin.Forms\n\ntype Model =\n    { Count: int }\n\ntype Msg = \n    | Increment\n    | Decrement\n\n\/\/ \"let\" is kind of like C#'s \"var\", except it also declares functions\n\/\/ F# automatically returns the last value as the result of the function\nlet init () =\n    { Count = 0 }\n\n\/\/ \"match ... with\" is known as Pattern Matching\n\/\/ The \"{ variable with X = Y }\" means it creates a copy of the variable with the X field changed to another value\n\/\/ This is because FP favors immutability so existing values can't mutate directly, to change a value we need to copy it.\nlet update msg model =\n    match msg with\n    | Increment -&gt; { model with Count = model.Count + 1 }\n    | Decrement -&gt; { model with Count = model.Count - 1 }\n\n\/\/ Here, we are using declarative views.\n\/\/ It is only a description of what we'd like the UI to be. Fabulous will translate it to actual controls.\nlet view model dispatch =\n    View.ContentPage(\n        View.StackLayout(\n            orientation = StackOrientation.Horizontal,\n            verticalOptions = LayoutOptions.Center,\n            horizontalOptions = LayoutOptions.Center,\n            children = [\n                View.Button(\n                    text = \"-\",\n                    command = fun () -&gt; dispatch Decrement\n                )\n                View.Label(\n                    text = (sprintf \"Count: %i\" model.Count),\n                    fontSize = FontSize.fromNamedSize NamedSize.Title,\n                    verticalOptions = LayoutOptions.Center\n                )\n                View.Button(\n                    text = \"+\",\n                    command = fun () -&gt; dispatch Increment\n                )\n            ]\n        )\n    )\n\ntype App() as this =\n    inherit Xamarin.Forms.Application()\n\n    let runner =\n        XamarinFormsProgram.mkSimple init update view\n        |&gt; Program.withConsoleTrace\n        |&gt; XamarinFormsProgram.run this\n<\/code><\/pre>\n<p>That is it! A full Fabulous application in only a few lines of code. Even if you don&#8217;t know F#, it should be fairly easy to understand.<\/p>\n<p>Taking a closer look, we can see the 5(+1) major parts we discussed just before:\n* the state definition (aka <code>Model<\/code>)\n* the messages (aka <code>Msg<\/code>)\n* an <code>init<\/code> function telling us what the initial state is when the app starts \n* an <code>update<\/code> function telling us how the state changes according to the received message \n* a <code>view<\/code> function telling us what the UI should look like for a given state \n* and finally the <code>App<\/code> class starting the MVU loop and plugging it into Xamarin.Forms<\/p>\n<h2>Getting started with Fabulous for Xamarin.Forms<\/h2>\n<p>Getting started is super easy. Fabulous.XamarinForms comes with its own template so we can quickly start creating awesome apps.<\/p>\n<p>In addition to <a href=\"https:\/\/dotnet.microsoft.com\/download\">.NET Core 3.1<\/a>, Fabulous.XamarinForms has the same set of requirements than Xamarin.Forms, namely:<\/p>\n<ul>\n<li>An IDE: Visual Studio (Windows), Visual Studio for Mac, JetBrains Rider or even MonoDevelop on Linux <\/li>\n<li>`The Xamarin tooling: See the documentation of Xamarin for your IDE to install it.<\/li>\n<\/ul>\n<p>First, install the templates on your machine with the following command:<\/p>\n<pre><code>dotnet new -i Fabulous.XamarinForms.Templates\n<\/code><\/pre>\n<p>Now, we can run <code>dotnet new fabulous-xf-app<\/code> to create our own Todo List app:<\/p>\n<pre><code>dotnet new fabulous-xf-app --name TodoList\n<\/code><\/pre>\n<p>By default this command will create a solution with a .NET Standard 2.0 library, a Xamarin.Android and a Xamarin.iOS projects. This template can optionally include more platforms like macOS, WPF, UWP and GTK. <a href=\"https:\/\/fsprojects.github.io\/Fabulous\/Fabulous.XamarinForms\/index.html#getting-started\">You can learn more in the documentation<\/a>.<\/p>\n<h3>Writing a To-Do List App<\/h3>\n<p>After knowing the fundamentals and have created a project, we can write a simple to-do list app by replacing parts of the template little by little.<\/p>\n<p>First, pause and think about what data our application will need. We are making a to-do list, so obviously we will need a list of to-dos. Also we want the user to add new to-dos, so we will need to track what the user inputted. This translates to a <code>To-do<\/code> record and a <code>Model<\/code> holding a list of <code>To-do<\/code>s and the current <code>Entry<\/code>&#8216;s text.<\/p>\n<pre><code class=\"fs\">type Todo =\n    { Task: string }\n\ntype Model =\n    { Todos: Todo list\n      EntryText: string }\n<\/code><\/pre>\n<p>We can now define our initial state in the <code>init<\/code> function.<\/p>\n<pre><code class=\"fs\">let init () =\n    { Todos = []; EntryText = \"\" }\n<\/code><\/pre>\n<p>Time to focus on the interactions available in our application. We want to let the user add new to-dos and remove old ones. Additionally, we want to retrieve what the user wrote so we can add it to the list.<\/p>\n<p>Two actions and one event, we can create those three entries in our <code>Msg<\/code> union. Notice how discriminated unions in F# make it super easy. You can even attach different types of data to each entry.<\/p>\n<pre><code class=\"fs\">type Msg =\n    | AddTodoFromEntryText\n    | RemoveTodo of Todo\n    | EntryTextChanged of string\n<\/code><\/pre>\n<p>We have our state, we have our messages. Now, we need to define how the state should change depending on the message in the <code>update<\/code> function.<\/p>\n<pre><code class=\"fs\">let update msg model =\n    match msg with\n    | AddTodoFromEntryText -&gt;\n        \/\/ Because list is actually a linked list, it is better to prepend new items with \"::\"\n        \/\/ We will reverse the list on the screen so new items are at the end\n        \/\/ Also we reset the Entry field since we inserted the new todo\n        let newTodo = { Task = model.EntryText }\n        { model with Todos = newTodo :: model.Todos; EntryText = \"\" }\n\n    | RemoveTodo todo -&gt;\n        \/\/ Filter out the old todo\n        let filteredTodos = model.Todos |&gt; List.filter (fun t -&gt; t &lt;&gt; todo)\n        { model with Todos = filteredTodos }\n\n    | EntryTextChanged newText -&gt;\n        { model with EntryText = newText }\n<\/code><\/pre>\n<p>One neat thing with pattern matching is that the F# compiler will warn you if you are missing a case.<\/p>\n<h3>Using Xamarin.Forms<\/h3>\n<p>We are nearly done. Let us describe what our UI should look like. You will find all the Xamarin.Forms controls under the <code>View<\/code> module.<\/p>\n<p>Unlike Xamarin.Forms, Bindings and Converters don&#8217;t exist in Fabulous. Instead you simply associate the value you want from the model to the corresponding property. Since Fabulous will call the <code>view<\/code> function each time the state changes, it will automatically detect changed fields just like bindings would.<\/p>\n<p>So, what do we want to display? A title would be nice. Also the list of to-dos is pretty important. Lastly, we need to display a field and a button so the user can add new to-dos. Once a to-do is done, we will let the user slide left on the to-do to reveal a &#8220;Complete&#8221; button to remove it from the list.<\/p>\n<p>All this translates to the following code:<\/p>\n<pre><code class=\"fs\">let view model dispatch =\n    View.ContentPage(\n        View.StackLayout(\n            padding = (\n                \/\/ Here the view is written in F#, so nothing prevents us from using F# code or even call other functions\n                \/\/ Really useful when the view is becoming too complex or should be reused, it can be split in several chunks\n                if Device.RuntimePlatform = Device.iOS then\n                    Thickness(20., 40., 20., 20.)\n                else\n                    Thickness(20., 0.)\n            ),\n            children = [\n                \/\/ Title\n                View.Label(\n                    text = \"My To-Do list\",\n                    fontSize = FontSize.fromNamedSize NamedSize.Title,\n                    horizontalOptions = LayoutOptions.Center\n                )\n\n                \/\/ Add new todo\n                View.Grid(\n                    coldefs = [ Star; Auto ],\n                    children = [\n                        View.Entry(\n                            text = model.EntryText,\n\n                            \/\/ `dispatch` here is a function provided by Fabulous that lets you send messages\n                            \/\/ when an event you want to react to happen. Here for example, whenever the text\n                            \/\/ of the Entry changes, an `EntryTextChanged` message will be sent.\n                            textChanged = fun e -&gt; dispatch (EntryTextChanged e.NewTextValue)\n                        )\n\n                        View.Button(\n                            text = \"Add todo\",\n                            command = fun () -&gt; dispatch AddTodoFromEntryText\n                        ).Column(1)\n                    ]\n                )\n\n                \/\/ Todo list\n                View.ListView([\n                    \/\/ Notice the \"List.rev\" function, it reverses our list\n                    \/\/ so the new todos are displayed at the end\n                    for todo in List.rev model.Todos -&gt;\n                        View.TextCell(\n                            text = todo.Task,\n                            contextActions = [\n                                View.MenuItem(\n                                    text = \"Complete\",\n                                    command = fun () -&gt; dispatch (RemoveTodo todo)\n                                )\n                            ]\n                        )\n                ])\n            ]\n        )\n    )\n<\/code><\/pre>\n<p>Finally, let&#8217;s update our program definition.<\/p>\n<pre><code class=\"fs\">let program = XamarinFormsProgram.mkSimple init update view\n<\/code><\/pre>\n<h3>Using a &#8220;Simple&#8221; program<\/h3>\n<p>Here we are using something called a &#8220;simple&#8221; program. Simple programs only need a state and messages.<br \/>\nTypically in real applications, use the <code>mkProgram<\/code> function instead to be able to execute side effects like asynchronously calling a web API.<\/p>\n<p>And voil\u00e0! We are done. We have our To-do list app. Find the whole <a href=\"https:\/\/gist.github.com\/TimLariviere\/fbd015030cc28f6698f15d9114dceb16\">source code of this To-do list app on GitHub<\/a>. Run this application and see the result.<\/p>\n<p><center>\n  <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/xamarin\/wp-content\/uploads\/sites\/44\/2020\/09\/todo-list-app.gif\" alt=\"Image todo list app\" width=\"200\" class=\"aligncenter size-full wp-image-47916\" \/>\n<\/center><\/p>\n<h3>More Real-World Apps<\/h3>\n<p>Regarding performance, Fabulous is really efficient and uses various diffing technics to do minimal changes between each updates. For more advanced scenarios, some tools are available to get better performance (see <a href=\"https:\/\/fsprojects.github.io\/Fabulous\/Fabulous.XamarinForms\/views-perf.html\">keyed nodes and view caching<\/a>).<\/p>\n<p>When your app gets bigger, easily scale it by breaking it down into independent components and stitch them together into a full app. MVU&#8217;s <code>init<\/code>\/<code>update<\/code>\/<code>view<\/code> loop is pretty generic and can be used on any level: application, page, component. Each thing being its own mini-Fabulous program with its own state, functions and UI. The parent component is responsible for calling the functions of its children components and keeping their states.<\/p>\n<p>If you want to see this in action, you can take a look at <a href=\"https:\/\/github.com\/TimLariviere\/FabulousContacts?WT.mc_id=fabulous-blog-jamont\">FabulousContacts<\/a>. It is a full application that manages your contacts, with database, maps and multiple pages.<\/p>\n<h2>Conclusion<\/h2>\n<p>App development using functional programming can make for a really great development experience. The combination of functional programming, MVU and F# allows you to write small codebase apps that are robust and easy to understand! Fabulous removes most hurdles of typical app development by centralizing all updates in one well-defined code path, preventing state to change unknowingly and making sure no concurrency issues can happen.<\/p>\n<p>Fabulous.LiveUpdate (similar to Xamarin.Forms Hot Reload) can even let you see your changes in near-realtime on your device or emulator. Check out the videos of The Xamarin Show on Channel9 to learn more about Fabulous and see LiveUpdate in action.<\/p>\n<p><center>\n<\/center><\/p>\n<p><iframe src=\"https:\/\/channel9.msdn.com\/Shows\/XamarinShow\/Introduction-to-Fabulous-a-F-MVU-Framework-for-Xamarin--The-Xamarin-Show\/player\" width=\"480\" height=\"270\" allowFullScreen frameBorder=\"0\" title=\"Introduction to Fabulous a F# MVU Framework for Xamarin | The Xamarin Show - Microsoft Channel 9 Video\"><\/iframe><\/p>\n<p><iframe src=\"https:\/\/channel9.msdn.com\/Shows\/XamarinShow\/FSharp-Fabulous-Beyond-MVU-Basics\/player\" width=\"480\" height=\"270\" allowFullScreen frameBorder=\"0\" title=\"F# Fabulous - Beyond MVU Basics | The Xamarin Show - Microsoft Channel 9 Video\"><\/iframe><\/p>\n<p>If you want to learn more about F#, check out the <a href=\"https:\/\/fsharpforfunandprofit.com\/\">F# for fun and profit<\/a> website which nicely introduces F# to C# programmers. <a href=\"https:\/\/fsharp.org\">fsharp.org<\/a> has you covered on all the topics. For a broader view of Fabulous and its ecosystem, you can learn more on my blog: <a href=\"https:\/\/timothelariviere.com\/2019\/12\/21\/how-to-become-a-fabulous-developer\/\">How to become a Fabulous developer<\/a>.<\/p>\n<p>Also make sure to visit our GitHub repository for all the latest bits: <a href=\"https:\/\/github.com\/fsprojects\/Fabulous?WT.mc_id=fabulous-blog-jamont\">https:\/\/github.com\/fsprojects\/Fabulous<\/a>.<\/p>\n<p>We welcome all contributions, either through issues, discussions or pull requests.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to get started with functional programming with Xamarin, F#, and Fabulous to create amazing native mobile apps. Guest blogger and Fabulous maintainer Timoth\u00e9 Larivi\u00e8re walks you through what Fabulous is, how to get started, and how to build real world functional native mobile apps.<\/p>\n","protected":false},"author":39433,"featured_media":47917,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2,367],"tags":[9162,713,9160,9010,9019,9161],"class_list":["post-47910","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","category-xamarin-forms","tag-app-development","tag-f","tag-fabulous","tag-mobile-applications","tag-mobile-apps","tag-mvu"],"acf":[],"blog_post_summary":"<p>Learn how to get started with functional programming with Xamarin, F#, and Fabulous to create amazing native mobile apps. Guest blogger and Fabulous maintainer Timoth\u00e9 Larivi\u00e8re walks you through what Fabulous is, how to get started, and how to build real world functional native mobile apps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/47910","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/39433"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=47910"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/47910\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/47917"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=47910"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=47910"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=47910"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}