Yesod Web Framework Blog2021-02-17T02:21:04-00:00/Yesod Web Framework Team/blog/2021/02/chatwisely-intro2021-02-17T02:21:04-00:00We Made ChatWisely With Haskell<p>Three years ago, I met fellow Haskeller Brian Hurt while working with Obsidian Systems on a Reflex project. Not long after, he started telling me his ideas about how to fix social media. These ideas intrigued me, one thing led to another, and we began building ChatWisely. We thought other Haskellers might like to hear about what we’re doing and how we use Haskell to do it.</p><p>ChatWisely is a member-supported mini-blogging social network currently in open beta. We envision a place where people connect in a spirit of comradery. We see an elevated discourse and a way to show bullies the door by providing a platform to debate safely. Here’s how we’re doing it.</p><h2 align=center>Safety First</h2>
Brian and I built several mechanisms to filter out people looking for a fight or to harm others. First and foremost will be the monthly subscription fee of one dollar. We think that will discourage a large portion of toxic people. Another is a sharable mute list that we believe will help mitigate the rest. And finally, in the event of a serious Terms of Service violation, we ban payment methods rather than just accounts. <h2 align=center>Mini-Blogging</h2>
The big idea here is that sometimes, a short post isn’t enough. Brian and I made a way to link that short post to a longer one. So the timeline looks something like Twitter’s, but with some posts that can expand to something more detailed. These can be connected to other people’s posts to create a continuity in conversation hard to come by on other platforms. So when another member’s post inspires you to write a longer one about your experience with the ghcjs ffi (for example), you can link your post to theirs.<h2 align=center>Ownership of Your Timeline</h2>
Members can organize their timeline and choose to what extent they follow other people’s posts. The typical mainstream social network requires that when you follow someone you must follow everything they post, or nothing. Sure, there are filtered word lists in some cases. But none of it seems to work quite right. Instead, we have groups called caboodles that members can use to decide where other people’s posts fit, and how to share their own. So say someone likes their uncle’s cookie recipes but not his political posts. They can follow one but not the other.<h2 align=center>Geolocated Messaging</h2>
One day this pandemic will be over and we’ll be there to meet that day. At that time, when a member’s movie caboodle wants to organize local screenings of the latest blockbuster from the House of Mouse they can make posts visible to people in their proximity. Perhaps you want to target local Haskellers to organize a meetup, or leave them a message that pops up when they’ve found the meeting place. Also, I think running a scavenger hunt with geolocated clues sounds like a hoot.<h2 align=center>How It’s Built</h2>
Brian and I rely heavily on the Haskell ecosystem to build ChatWisely. Haskell’s type system reduces errors and cognitive load. GHC is our pair programming partner that tightens the delivery cycle and lets us learn how to build ChatWisely while we’re building it. Refactoring is a breeze, and unit testing is constrained to the I/O edges of the system, which means we spend less time on that and more time building the product. Here’s the principal tools we rely on to get the job done.
<br/> <br/>
<h4> Ghcjs </h4> The fact is we all hate javascript. The problem is, we can’t build web apps without it. Ghcjs lets us deal with the realities of building a product that uses a web browser for a client. The FFI lets us wrap our hand-written javascript in Haskell which helps to keep that part of the codebase pretty small.. We especially love what is built on top of that, Reflex-Dom.<h4> Reflex-Dom </h4> Reflex helps us build a system that needs to adapt to changes in data, requirements and platform. We’re learning how to build ChatWisely as we build it, and reflex keeps up with our changing ideas on how to do that. Our first app store product will be a PWA, delivered with reflex.<h4> Servant </h4> Servant delivers the API, and requires us to separate definition from implementation. This helps us keep the backend from turning into a big ball of mud. We can auto-generate clients, which we currently use in unit testing. They even have a way to generate a reflex client, and we’ll be adding that in the near future.<h4>Yesod</h4> We use Yesod for marketing tasks, which largely require static pages. Currently it handles our landing page and unsubscribe mechanism for our emails. The Yesod Widget is a monoid, and therefore composable, which makes structuring html simple. <h2 align=center>Three Reasons Why People Should Use ChatWisely.</h2>
<h4>We are member supported</h4> We won’t have ads, which means we have no need to manipulate people’s timelines in order to serve those ads. Their timeline should be about conversations of interest.<h4>We solve the tweet thread problem</h4>Brian and I find tweet threads hard to follow. Our mini-blog looks like twitter in the sense that you get a timeline of short posts. However if a post is the beginning of something more developed, that message can open up to access it.<h4>Keep the RealWorld conversation going</h4>We have delayed the development of these features for obvious reasons. But one day we’ll be together again. By then we’ll have useful geo-location tools for conference attendees and speakers to continue the conversation.<p>What makes a weekend conference fun for me are the conversations in-between formal talks. I get all caught up in compelling conversations, and want to keep that going. We’ll have a way to do that, without having to know or remember anyone’s email address or phone number.</p><p>Conference speakers will often want to build on the momentum gathered after a successful talk. Brian and I think Twitter hashtags are the terrible but often only way to do this. We’ll have a way to use proximity and common interests to help build that momentum and keep everyone engaged.</p><hr><p>We built ChatWisely as a response to the unpleasantness all too common on mainstream social networks. Depending on our membership for support creates the place we want to meet because ad revenue and data-mining motivates engagement, not conversations and connection. No one is fooled by what mainstream social networks call engagement because that looks to us like derailed conversations, confusing timelines we only have a shallow control over, and unsafe situations.</p><p>Brian and I love the daily experience of building ChatWisely, the Haskell ecosystem brings joy to the experience of running our startup. You can support us on <a href="https://www.patreon.com/chatwisely">patreon</a> and should come by and test the <a href="https://chatwisely.com/i/messages">beta</a>. We look forward to hearing from you about any ideas or questions you may have.</p>/blog/2020/05/blogannouncement2020-05-03T18:35:00-00:00A new Haskell/Yesod Beginners Blog<p>This is the annoncement for a new Haskell Beginners Blog, which first series of articles will handle the building of two Yesod-projects: a personal Blog with slighly powered batteries and in addition examples of functionality from a small-buisiness-website.</p><p>As I have decided to learn Haskell late and not long ago, this Blogpost is written out of a straight programming beginners point of view, and like so will handle also prelimiaries and standarts maybe annoying to people with a different background.</p><p>I was a bit afraid to use Yesod as a first step in my learning Haskell journey - you all know it is a big, non trival framework - but somehow, after a while of proving and looking into it, I felt quite save and secure to not miss the point. I mean, moving around in it's structure felt somehow good and plausible. Hope to transport that in this Blog.</p><p><a href="https://blog.onepigayear.de">https://blog.onepigayear.de</a></p>/blog/2019/12/bookportuguese2019-12-19T03:29:00-00:00A new Yesod book in Portuguese<p>Yesod users,</p><p>In order to help to spread the Yesod word here in Brazil, we, <a href="https://github.com/romefeller">Alexandre Garcia de Oliveira</a>, <a href="https://github.com/ptkato">Patrick Augusto da Silva</a> (<a href="https://twitter.com/ptkato_"><code>@ptkato_</code></a> on Twitter), and
<a href="https://github.com/cannarozzo">Felipe Cannarozzo Lourenço</a>, wrote a book, recently released, about Yesod
called <a href="https://www.casadocodigo.com.br/products/livro-yesod-haskell">"Yesod e Haskell: Aplicações web com Programação Funcional pura"</a> ("Yesod and Haskell: Web
applications with pure Functional Programming", in English).</p><p>The book covers the principles of developing a web application with Yesod. Needless
to say, it follows the same model of Alexandre's first book on Haskell, giving a much needed
insight into the Yesod world within the Brazilian borders.</p><p>The book aims to allow the reader to learn Yesod from scratch, starting from the basics, like setting up
the environment using stack, and using a monolithic example in a single file, to explain the foundations of
the framework. The book goes through the Stackage's snapshots, the difference between templates and
scaffolding, Shakespearean Templates, <i>type-safe</i> routing, persistent basics, authentication &
authorization, finishing up with a RESTful app example.</p><p>The idea of writing a book about Yesod came to fruition during one of Alexandre's lectures on Yesod at
<a href="https://fatecrl.edu.br">FATEC-Santos</a>, when it was realized that many students didn't read English at all
and Yesod documentation in Portuguese was virtually non-existent. Not only that,
the volition to write this book became even stronger when the TAs' (Patrick and Felipe) tutoring classes were almost always spent on going through the same topics, when Portuguese documentation could have easily solved the problem.</p><p>All the pedagogic skills to write this book were founded on top of the fact that it was written in an
academic medium, considering that, it was shaped in such a way that fits the needs of an undergrad student
fairly well. Now, hundreds of FATEC-Santos alumni experienced the joy of using Yesod, Santos indeed is the
city in Brazil with the highest number of people who knows Yesod. We're committed to pushing Yesod forward through the local market, and maybe in the future, even beyond.</p><p>The book was published by "Casa do Código" and can be found <a href="https://www.casadocodigo.com.br/products/livro-yesod-haskell">here</a>.</p>/blog/2019/02/deprecating-googleemail22019-02-12T15:49:00-00:00Deprecating GoogleEmail2<p>As I'm sure many readers are aware, Google+ is shutting down. This
<a href="https://github.com/yesodweb/yesod/issues/1579">affects Yesod's authentication
system</a>. In particular,
any users of the <code>Yesod.Auth.GoogleEmail2</code> module will need to
migrate.</p><p>Fortunately for all of us, Patrick Brisbin has written both <a href="https://www.stackage.org/haddock/lts-13.7/yesod-auth-oauth2-0.6.1.0/Yesod-Auth-OAuth2-Google.html">the
code</a>
for using Google Sign-in, but has also put together <a href="https://pbrisbin.com/posts/googleemail2_deprecation/">a great migration
blog post</a>. If
you're affected, please check that out for a relatively painless
migration.</p><p>Earlier today, I migrated Haskellers.com in two commits: the <a href="https://github.com/snoyberg/haskellers/commit/f77bba90d9684afb532639c68e64449523992535">first
did all of the
work</a>,
and the <a href="https://github.com/snoyberg/haskellers/commit/68198eb05389a96fe3250d2f3e179364531faca5">second made things more
future-proof</a>.</p><p>As you may be able to tell from the <code>GoogleEmail2</code> module, this isn't
the first time we've had to migrate between Google authentication
APIs. Hopefully this one will stick.</p>/blog/2018/01/upcoming-yesod-breaking-changes2018-01-11T21:29:00-00:00Upcoming Yesod breaking changes<p>With all of the talk I've had about breaking changes in my libraries,
I definitely didn't want the Yesod world to feel left out. We've been
stable at yesod-core version 1.4 since 2014. But the changes going
through my package ecosystem towards <code>MonadUnliftIO</code> are going to
affect Yesod as well. The question is: how significantly?</p><p>For those not aware, <code>MonadUnliftIO</code> is an alternative typeclass to
both <code>MonadBaseControl</code> and the <code>MonadCatch</code>/<code>MonadMask</code> classes in
<code>monad-control</code> and <code>exceptions</code>, respectively. I've mentioned the
advantages of this new approach in a number of places, but the best
resource is probably the
<a href="https://www.fpcomplete.com/blog/2017/07/announcing-new-unliftio-library">release announcement blog post</a>.</p><p>At the simplest level, the breaking change in Yesod would consist of:</p><ul><li>Modifying <code>WidgetT</code>'s internal representation. This is necessary
since, currently, it's implemented as a <code>WriterT</code>. Instead, to match
with <code>MonadUnliftIO</code>, it needs to be a <code>ReaderT</code> holding an
<code>IORef</code>. This is just about as minor a breaking change as I can
imagine, since it only affects internal modules. (Said another way:
it could even be argued to be a non-breaking change.)</li><li>Drop the <code>MonadBaseControl</code> and <code>MonadCatch</code>/<code>MonadMask</code>
instances. This isn't strictly necessary, but has two advantages: it
allows reduces the dependency footprint, and further encourages
avoiding dangerous behavior, like using <code>concurrently</code> with a
<code>StateT</code> on top of <code>HandlerT</code>.</li><li>Switch over to the new versions of the dependent libraries that are
changing, in particular conduit and resourcet. (That's not
technically a breaking change, but I typically consider dropping
support for a major version of a dependency a semi-breaking change.)</li><li>A number of minor cleanups that have been waiting for a breaking
changes. This includes things like adding strictness annotations in
a few places, and removing the defunct <code>GoogleEmail</code> and <code>BrowserId</code>
modules.</li></ul><p>This is a perfectly reasonable set of changes to make, and we can
easily call this Yesod 1.5 (or 2.0) and ship it. I'm going to share
one more slightly larger change I've experimented with, and I'd
appreciated feedback on whether it's worth the breakage to users of
Yesod.</p><h2>Away with transformers!</h2><p><i>NOTE</i> All comments here, as is usually the case in these discussions,
refer to code that must be in <code>IO</code> anyway. Pure code gets a pass.</p><p>You can check out the changes (which appear larger than they actually
are) in
<a href="https://github.com/yesodweb/yesod/pull/1466">the <code>no-transformers</code> branch</a>. You'll
see shortly that that's a lie, but it does accurately indicate
intent. If you look at the pattern of the blog posts and recommended
best practices I've been discussing for the past year, it ultimately
comes down to a simple claim: we massively overuse monad transformers
in modern Haskell.</p><p>The most extreme response to this claim is that we should get rid of
<i>all</i> transformers, and just have our code live in <code>IO</code>. I've made a
slight compromise to this for ergonomics, and decided it's worth
keeping reader capabilities, because it's a major pain (or at least
<i>perceived</i> major pain) to pass extra stuff around for, e.g., simple
functions like <code>logInfo</code>.</p><p>The core data type for Yesod is <code>HandlerT</code>, with code that looks like
<code>getHomeR :: HandlerT App IO Html</code>. Under the surface, <code>HandlerT</code>
looks something like:</p><pre><code class="haskell">newtype HandlerT site m a = HandlerT (HandlerData site -> m a)</code></pre><p>Let's ask a simple question: do we really need <code>HandlerT</code> to be a
transformer? Why not simply rewrite it to be:</p><pre><code class="haskell">newtype HandlerFor site a = HandlerFor (HandlerData site -> IO a)</code></pre><p>All we've done is replaced the <code>m</code> type parameter with a concrete
selection of <code>IO</code>. There are already assumptions all over the place
that your handlers will necessarily have <code>IO</code> as the base monad, so
we're not really losing any generality. But what we gain is:</p><ul><li>Slightly clearer error messages</li><li>Less type constraints, such as <code>MonadUnliftIO m</code>, floating around</li><li>Internally, this actually simplifies quite a few ugly things around
weird type families</li></ul><p>We can also regain a lot of backwards compatibility with a helper type
synonym:</p><pre><code class="haskell">type HandlerT site m = HandlerFor site</code></pre><p>Plus, if you're using the <code>Handler</code> type synonym generated by the
Template Haskell code, the new version of Yesod would just generate
the right thing. Overall, this is a slight improvement, and we need to
weigh the benefit of it versus the cost of breakage. But let me throw
one other thing into the mix.</p><h2>Handling subsite (yes, transformers)</h2><p>I lied, twice: the new branch <i>does</i> use transformers, and <code>HandlerT</code>
<i>is</i> more general than <code>HandlerFor</code>. In both cases, this has to do
with subsites, which have historically been a real pain to write
(using them hasn't been too bad). In fact, the entire reason we have
<code>HandlerT</code> today is to try and make subsites work in a nicely layered
way (which I think I failed at). Those who have been using Yesod long
enough likely remember <code>GHandler</code> as a previous approach for this. And
anyone who has played with writing a subsite, and the hell which
ensues when trying to use <code>defaultLayout</code>, will agree that the
situation today is not great.</p><p>So cutting through all of the crap: when writing a subsite, almost
everything is the same as writing normal handler code. The following
differences pop up:</p><ul><li>When you call <code>getYesod</code>, you get the master site's app data
(e.g. <code>App</code> in a scaffolded site). You need some way to get the
subsite's data as well (e.g., the <code>Static</code> value in <code>yesod-static</code>).</li><li>When you call <code>getCurrentRoute</code>, it will give you a route in the
master site. If you're inside <code>yesod-auth</code>, for instance, you don't
want to deal with all of the possible routes in the parent, but
instead get a route for the subsite itself.</li><li>If I'm generated URLs, I need some way to convert the routes for a
subsite into the parent site.</li></ul><p>In today's Yesod, we provide these differences inside the <code>HandlerT</code>
type itself. This ends up adding some weird complications around
special-casing the base (and common) case where <code>m</code> is <code>IO</code>. Instead,
in the new branch, we have just one layer of <code>ReaderT</code> sitting on top
of <code>HandlerFor</code>, providing these three pieces of functionality. And if
you want to get a better view of this,
<a href="https://github.com/yesodweb/yesod/blob/3e06942449cad0b52e218cb7e9f2c06b45b85e69/yesod-core/Yesod/Core/Class/Dispatch.hs#L38">check out the code</a>.</p><h2>What to do?</h2><p>Overall, I think this design is more elegant, easier to understand,
and simplifies the codebase. In reality, I don't think it's either a
major departure from the past, or a major improvement, which is what
leaves me on the fence about the no transformer changes.</p><p>We're almost certainly going to have a breaking change in Yesod in the
near future, but it need not include this change. If it doesn't, the
breaking change will be the very minor one mentioned above. If the
general consensus is in favor of this change, then we may as well
throw it in at the same time.</p>