-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathBuilding-an-MVP-with-F-and-Saturn.html
366 lines (239 loc) · 20.9 KB
/
Building-an-MVP-with-F-and-Saturn.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Building an MVP with F# and Saturn</title>
<meta name="description" content="Building an MVP with F# and Saturn">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="/favicon/favicon.ico">
<link rel="apple-touch-icon-precomposed" href="/favicon/lattice-optic-illusion-152-204321.png" >
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-TileImage" content="/favicon/lattice-optic-illusion-144-204321.png">
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Lato:400,400italic,700,700italic" />
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/styles/default.min.css">
<link rel="stylesheet" href="/css/main.css" />
<link rel="stylesheet" href="/css/font-awesome.min.css" />
<link rel="canonical" href="http://localhost:4000/Building-an-MVP-with-F-and-Saturn">
<link rel="alternate" type="application/rss+xml" title="F# Reflections Feed" href="http://localhost:4000/feed.xml">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
</head>
<body>
<nav id="top" class="site-navigation">
<div class="inner">
<button id="menu-toggle" aria-expanded="false">Menu</button>
<div class="nav-menu">
<ul class="menu">
<li class="">
<a class="" href="/">Home</a>
</li>
<li class="">
<a class="" href="/about">About</a>
</li>
<li class="">
<a class="" href="/tags/">Archives</a>
</li>
<li class="">
<a class="" href="/2016">2016</a>
</li>
</ul>
</div><!-- .nav-menu -->
<div class="subscribe-button">
<a class="fa-feed square fill-horizontal" href="/feed.xml"><span class="screen-reader-text">RSS</span></a>
</div><!-- .social-links -->
</div><!-- .inner -->
</nav><!-- .site-navigation -->
<header class="site-header">
<div class="inner">
<h1 class="site-title"><a class="logo-text" href="/">F# Reflections</a></h1>
<p class="site-description">Thoughts, stories and ideas.</p>
</div><!-- .inner -->
</header>
<div class="site-content">
<div class="inner">
<main class="site-main">
<article class="post">
<header class="entry-header">
<div class="entry-header-wrap">
<div class="post-thumbnail">
<img src="/images/posts/landscape_13.jpg" alt="Building an MVP with F# and Saturn">
</div><!-- .post-thumbnail -->
<h1 class="entry-title">Building an MVP with F# and Saturn</h1>
</div><!-- .entry-header-wrap -->
<div class="entry-meta">
by <span class="post-author">Krzysztof Cieslak</span> on <time class="published" datetime="2018-08-16">August 16, 2018</time>
</div><!-- .entry-meta -->
</header><!-- .entry-header -->
<div class="entry-content">
<h1>Building an MVP with F# and Saturn</h1>
<p>Creating an MVP (minimum viable product) is one of the best way of bootstrapping your startup. As a new company getting a quick feedback from the application users, bringing an application to users as fast as possible, being able to adapt as quickly as possible to the market changes, and providing frequent application updates is crucial for the initial success of the product. But it’s also important to understand that an MVP software development is not synonymous with unfinished or a primitive product that was created in a hurry.</p>
<!--more-->
<h3>What is an MVP?</h3>
<p>Minimum Viable Product (MVP) is the smallest, most concise version of your product you can initially release for feedback. It enables a full turn of the feedback loop with the least amount of development time and effort. This allows the targeted users to try a product and evaluate it to make the complete version better. It is a frequently updated environment with the new features that could be seen and tested by clients. New registration page, an admin management panel, as well as email notifications, and any other new features you can imagine.</p>
<p>MVP development allows early adopters to understand the vision or promise of the final product and provide valuable feedback to guide developers moving forward. The main advantages of the MVP software development are:</p>
<ul>
<li>
<p>MVP has enough value that people can already use or buy it</p>
</li>
<li>
<p>It demonstrates enough features to hook and retain early users</p>
</li>
<li>
<p>It provides feedback loop to guide future development</p>
</li>
<li>
<p>It shows enough future potential to start marketing around the project</p>
</li>
</ul>
<p>What’s important - MVP development is not only the strategy for startups. When you already have well-established company and customers, you also need to have some way to experiment with new potential products or features. In a lot of cases, the minimum viable product really is just a way to do that.</p>
<h3>Few words about F#</h3>
<p><a href="https://fsharp.org">F# is a functional-first programming language</a> running on the .Net platform. Paired with <a href="https://www.microsoft.com/net">.Net Core</a> - modern, cross platform implementation of the .Net Framework - it is fantastic tool for writing modern applications. .Net Core provides industrial level of the performance, security, huge ecosystem of the libraries, and always growing open source community. F#, itself an open source language with fantastic community , thanks to expressiveness, functional-first approach, great developers tooling and advanced language features provides unmatched developer experience and fast development speed, so important for building MVPs. It can also be your secret weapon that makes you stand out from many different companies, and that let you hire more talented people that just want to work with more niche technology.</p>
<h3>Introducing Saturn</h3>
<p>F# due to its functional nature is perfect fit for the web applications. In the end HTTP web server may be treated as a function that takes Request and returns Response.</p>
<p><a href="https://saturnframework.org">Saturn</a> is a modern web framework for the F# focusing on high level abstractions and great developer experience, allowing developers focus on the things that matters for your business. Influenced by the popular frameworks such as Rails or Phoenix it comes with all the batteries included. Its ecosystem includes development tools that allows developers to quickly create new applications, add new features to existing applications, and test new features; it integrates with existing <a href="https://docs.microsoft.com/en-us/aspnet/core/?view=aspnetcore-2.1">ASP.NET Core</a> ecosystem that provides huge set of existing modules that you can use in your application; it provides pre-defined configurations that limits the number of decisions that developers need to make. And all this while using highly expressive and modern programming language.</p>
<h3>Typical difficulties</h3>
<p>While MVP development is really powerful technique, just like every other methodology it has its own drawbacks. First of all you need to understand it’s not about delivering product as fast as possible so customers can try it out. MVP development is about refined and validated learning. This simple fact must be understood by everyone - stakeholders, developers, customers. You have to understand that final product may drastically change due to user’s feedback. And this is something that must be embraced by the development team, and should impact the way in which they work. Developers needs to have regular feedback session, learn from them, prioritise features.</p>
<p>As a result, this should have an impact on the technologies chosen for developing MVP:</p>
<ul>
<li>
<p>refactoring plays the key roles, when you see that some part of the product is not scalable or flexible enough, or that it just need changes based on the user’s feedback you need to be able to quickly change an existing code base</p>
</li>
<li>
<p>correctness is important, especially the one you can get for free. Using static type checking, code linting, and code quality tools is crucial to provide product that’s working well enough, without spending much development time on it</p>
</li>
<li>
<p>flexible but simple design - design of your product must be flexible enough to provide ability to change the product based on the feedback, but at the same time it must be relatively simple - for MVP development you want to get to the market as fast as possible, and you don’t want to spend time building sophisticated architecture that may not work after all changes that will happen in the future</p>
</li>
</ul>
<p>Fortunately, F# and .Net Core are great solutions for all those problems - functional first approach naturally pushes you toward pit of success, and simple, flexible architecture, static typing with powerful type inference enables you to create correct software without much overhead, best in class editor tooling helps you to quickly refactor existing code.</p>
<h3>Commercial support</h3>
<p>The last important factor in choosing right technology is having an ability to hire someone to develop the product, or just get help. F# ecosystem is including wide range of the options for getting commercial support - starting from the established companies providing support for <a href="https://safe-stack.github.io">SAFE Stack</a> through multiple independent consultants to <a href="https://lambdafactory.io">Lambda Factory</a>. Lambda Factory specialises in creating web applications, F# training and consulting, MVP development, and developer relationships. We provide everything you need to transform your startup into prospecting business - help with creating MVP, iterating over the feedback loop, hiring talented developers, and DevRel marketing.</p>
</div><!-- .entry-content -->
<footer class="entry-footer">
<div class="share-post">
<span>Share</span>
<a class="fa-twitter" target="_blank" href="https://twitter.com/intent/tweet?text=Building%20an%20MVP%20with%20F#%20and%20Saturn&url=http://localhost:4000/Building-an-MVP-with-F-and-Saturn"><span class="screen-reader-text">Twitter</span></a>
<a class="fa-facebook" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://localhost:4000/Building-an-MVP-with-F-and-Saturn&t=Building%20an%20MVP%20with%20F#%20and%20Saturn"><span class="screen-reader-text">Facebook</span></a>
<a class="fa-google-plus" target="_blank" href="http://plus.google.com/share?url=http://localhost:4000/Building-an-MVP-with-F-and-Saturn"><span class="screen-reader-text">Google+</span></a>
</div><!-- .share-post -->
<div class="tag-links">
Tags: <a href="/tags/index.html#F%23" title="Pages tagged F#" rel="tag">F#</a><a href="/tags/index.html#Saturn" title="Pages tagged Saturn" rel="tag">Saturn</a><a href="/tags/index.html#Web" title="Pages tagged Web" rel="tag">Web</a><a href="/tags/index.html#MVP" title="Pages tagged MVP" rel="tag">MVP</a>
</div>
</footer><!-- .entry-footer -->
</article><!-- .post -->
<div class="author-box">
<div class="author-info">
<a href="http://kcieslak.io/about" target="_blank"> <div class="author-avatar" style="background-image: url(/images/authorimage.jpg)"><span class="screen-reader-text">Krzysztof Cieslak's Picture</span></div> </a>
<div class="author-details">
<h2 class="author-title">About Krzysztof Cieslak</h2>
<p class="author-bio">Krzysztof is a F# developer and consultant, open source contributor, conference speaker</p>
<span class="author-location"><i class="fa-map-marker" aria-hidden="true"></i> Lodz, Poland</span>
<span class="author-website"><i class="fa-chain" aria-hidden="true"></i> <a href="http://kcieslak.io" target="_blank"> http://kcieslak.io</a></span>
</div><!-- .author-details -->
</div><!-- .author-info -->
</div><!-- .author-box -->
<nav class="post-navigation">
<h2 class="screen-reader-text">Post navigation</h2>
<div class="nav-previous">
<div class="nav-inside">
<a href="/Challenges-of-post-OSS-world" class="nav-thumb" style="background-image: url(/images/posts/landscape_12.jpg)"></a>
<div class="nav-before">Previous</div>
<div class="nav-title"><a href="/Challenges-of-post-OSS-world">Challenges of post-OSS world</a></div>
<div class="nav-date">August 11, 2018</div>
</div><!-- .nav-inside -->
</div><!-- .nav-previous -->
<div class="nav-next">
<div class="nav-inside">
<a href="/Introducing-F-Analyzers" class="nav-thumb" style="background-image: url(/images/posts/landscape_6.jpg)"></a>
<div class="nav-before">Next</div>
<div class="nav-title"><a href="/Introducing-F-Analyzers">Introducing F# Analyzers</a></div>
<div class="nav-date">September 14, 2018</div>
</div><!-- .nav-inside -->
</div><!-- .nav-next -->
</nav><!-- .post-navigation -->
</main><!-- .site-main -->
<aside class="sidebar">
<section class="widget widget-text">
<h2 class="widget-title">About Krzysztof Cieslak</h2>
<p>Krzysztof is a F# developer and consultant, open source contributor, conference speaker</p>
</section><!-- .widget-text -->
<section class="widget widget-text">
<p><a href="http://lambdafactory.io" target="_blank"><img src="/images/banner.png" alt="Optional Banner Ad" /></a></p>
</section><!-- .widget-text-->
<section class="widget widget-recent-posts">
<h2 class="widget-title">Latest Posts</h2>
<ul class="recent-posts">
<li class="recent-item"><a href="/F-Editor-Tooling-Part1">Behind the F# editor tootling. Part 1: introduction to compilers.</a> <span>August 27, 2019</span></li>
<li class="recent-item"><a href="/Ionide-Introducing-Info-Panel">Ionide — Introducing Info Panel</a> <span>May 6, 2019</span></li>
<li class="recent-item"><a href="/Ionide-New-Hope">Ionide — A New Hope</a> <span>March 24, 2019</span></li>
<li class="recent-item"><a href="/PureScript-on-Azure-Functions">PureScript on Azure Functions</a> <span>January 12, 2019</span></li>
<li class="recent-item"><a href="/Future-of-F-Cross-platform-editor-tooling">Future of F# cross-platform editor tooling</a> <span>December 31, 2018</span></li>
</ul><!-- .recent-posts -->
</section><!-- .widget-recent-posts -->
<!--Create a sorted array of tags-->
<section class="widget widget-tags">
<h2 class="widget-title">Tags</h2>
<div class="tagcloud">
<a href="/tags/#Azure">Azure</a>
<a href="/tags/#Azure+Functions">Azure Functions</a>
<a href="/tags/#Community">Community</a>
<a href="/tags/#Compiler">Compiler</a>
<a href="/tags/#F%23">F#</a>
<a href="/tags/#FAKE">FAKE</a>
<a href="/tags/#FSharp.Compiler.Services">FSharp.Compiler.Services</a>
<a href="/tags/#Fable">Fable</a>
<a href="/tags/#JS">JS</a>
<a href="/tags/#MVP">MVP</a>
<a href="/tags/#OAuth">OAuth</a>
<a href="/tags/#Open+Source">Open Source</a>
<a href="/tags/#Paket">Paket</a>
<a href="/tags/#PureScript">PureScript</a>
<a href="/tags/#Saturn">Saturn</a>
<a href="/tags/#Serverless">Serverless</a>
<a href="/tags/#Tooling">Tooling</a>
<a href="/tags/#VS+Code">VS Code</a>
<a href="/tags/#Web">Web</a>
<a href="/tags/#Webpack">Webpack</a>
</div><!-- .tagcloud -->
</section><!-- .widget -->
<section class="widget widget-text">
<h2 class="widget-title">Contact me</h2>
<a href="https://twitter.com/k_cieslak" class="fa-twitter square fill-horizontal"><span class="screen-reader-text">Twitter</span></a>
<a href="https://github.com/Krzysztof-Cieslak" class="fa-github-alt square fill-horizontal"><span class="screen-reader-text">GitHub</span></a>
<a href="https://gitlab.com/Krzysztof-Cieslak" class="fa-gitlab square fill-horizontal"><span class="screen-reader-text">GitHub</span></a>
<a href="mailto:[email protected]" class="fa-envelope square fill-horizontal"><span class="screen-reader-text">E-Mail</span></a>
</section><!-- .widget-text -->
</aside><!-- .sidebar -->
</div><!-- .inner -->
</div><!-- .site-content -->
<footer class="site-footer">
<div class="inner">
<div class="social-links">
<a href="https://twitter.com/k_cieslak" class="fa-twitter square fill-horizontal"><span class="screen-reader-text">Twitter</span></a>
<a href="https://github.com/Krzysztof-Cieslak" class="fa-github-alt square fill-horizontal"><span class="screen-reader-text">GitHub</span></a>
<a href="https://gitlab.com/Krzysztof-Cieslak" class="fa-gitlab square fill-horizontal"><span class="screen-reader-text">GitHub</span></a>
<a href="mailto:[email protected]" class="fa-envelope square fill-horizontal"><span class="screen-reader-text">E-Mail</span></a>
<a class="fa-feed square fill-horizontal" href="/feed.xml"><span class="screen-reader-text">RSS</span></a>
</div><!-- .social-links -->
<div class="site-info">
© <a href="/">Krzysztof Cieslak</a> all rights reserved. <br />Powered by <a target="_blank" href="https://jekyllrb.com/">Jekyll</a>. BlogInn theme by <a target="_blank" href="http://justgoodthemes.com/">JustGoodThemes</a>
<a href="#top" id="top-link" class="fa-chevron-up top-link square fill-horizontal"><span class="screen-reader-text">Back to the top</span></a>
</div><!-- .site-info -->
</div><!-- .inner -->
</footer><!-- .site-footer -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/highlight.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/languages/fsharp.min.js"></script>
<script type="text/javascript" src="/js/plugins.js"></script>
<script type="text/javascript" src="/js/custom.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
<!-- Asynchronous Google Analytics snippet -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-74514389-1', 'auto');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');
</script>
</body>
</html>