{ "version": "https://jsonfeed.org/version/1", "title": "James Forbes", "home_page_url": "https://james-forbes.com", "feed_url": "https://james-forbes.com/feed/json", "description": "Interested in any type of design and the individual componentry of calcified ideas.", "icon": "https://james-forbes.com/assets/img/bio.jpeg", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" }, "items": [ { "id": "https://james-forbes.com/posts/why-cohost-is-good", "content_html": "

,> Unfortunately Cohost is no longer a thing. But it is still a really fascinating case study on multiple fronts. It was extremely well received by its userbase, and ultimately the team just suffered from burn out and lack of funding. It will be interesting what future projects learn from Cohost.,,And why it might be important to remove gamification from our online social interactions.,,> Note there's no screenshots here, this is a big wall of text. I've been meaning to post something like this for a while and wall of text is all I can manage right now. Sorry.,,## Cohost? What is that?,,Cohost is a comparatively tiny social media website that is owned and operated by its development team. It also deliberately avoids metrics and gamification. Cohost doesn't care if you keep scrolling. Actually they do care, they want you to stop scrolling.,,I feel that the fact Cohost is operated as a co-op directly informs the product design, and that gives me a lot of confidence in its long term sustainability provided it can get overcome its current short term financial challenges.,,By avoiding investors and non-worker equity Cohost has a significant financial challenge to overcome before it can reach long term sustainability.,,Conversely I don't have a lot of faith in the long term sustainability of other social networks that only focus on the technical challenges of decentralization. Centralization was never the problem. Centralization can be incredibly efficient and simple. The problem was always a conflict of interests between the users, the workers and the owners. By collapsing owners and workers into a single category it is possible to still have conflict but workers have an interest in long term sustainability in a way that owners simply don't. Investors see products as interchangable and fungible assets, whereas workers naturally are more invested in the stability of their own income stream.,,In this post I am going to explore some of my thoughts on Cohost as product, the interesting features it has, and how those features relate to its business model and ultimate market fit.,,Another goal of this post is to potentially intrigue users to give it a go who otherwise wouldn't. I think Cohost is a great place for different groups to make their own little non-predatory corner of the internet. It may also be a great place to run small online businesses in the future.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/why-cohost-is-good", "title": "Why cohost is good", "date_modified": "2024-04-06T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/versatility-of-array-methods", "content_html": "

,Using array methods to replace conditionals, null checks and exception handling.,,Javascript arrays have some pretty useful helper methods. Usually we think of them as a handicapped Lodash or Ramda. Sure map and reduce is nice, but what about _.uniq or _.difference or _.groupBy.,,But Javascript has just enough building blocks to get by without pulling in additional libraries. And in es6 with arrow functions we can define new and interesting visitor functions without expending too much effort.,,But what I'd like to focus on in this post, is seeing these existing Array methods in a new light, as a replacement for if statements.,,### Dessert First,,By the end of this article you are going to be able to convert this code:,,```js,var results = [],for( var i = 0; i < list.length; i++ ){,, var a = list[i], var b = a && a.someProperty && a.someProperty.someSubProperty, try {

\n

Continued...

\n", "url": "https://james-forbes.com/posts/versatility-of-array-methods", "title": "The versatility of Array methods", "date_modified": "2017-01-25T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/things-to-keep-in-mind", "content_html": "

,- Why Everything Sucks (The Deification of the Youth) - Craig Ferguson,- The Art of Screenshake (Game Feel) - Jan Willem,- Utopian for Beginners (Ithkuil: A Philosophical Design for a Hypothetical Language.),- Music Object, Substance, Organism (David Kanaga),- Video Games and the Human Condition (Jon Blow),- Form and its Usurpers - Brendan Vance,- Design, Form and Chaos - Paul Rand,- The Possibilian - Burkhard Bilger,- Videogames and the Spirit of Capitalism - Paolo Pedercini,- Therefore, But and Meanwhile back at the Ranch,- Vulnerability - Katie Zhu,- How to Safely Store a Password - Coda Hale,- Splain it to Me - Alice Maz

\n

Continued...

\n", "url": "https://james-forbes.com/posts/things-to-keep-in-mind", "title": "Things to keep in mind", "date_modified": "2014-09-06T03:08:14.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/the-power-is-yours", "content_html": "

,This post is directed at anyone who is interested in the Fantasy Land specification but perhaps feels unqualified to discuss it or engage with the community. Functional Programming is for everyone, and so is Fantasy Land. Fantasy Land is for the JS community to build upon when designing libraries, frameworks and the language itself. Fantasy Land benefits as both a community and a specification from the participation of every developer, from every discipline. ,,> Fantasy Land is a specification for supporting Algebraic types in Javascript. Algebraic types are just data structures that obey some laws. ,>,> If you use Observables, Promises, Arrays or Strings you are already using Algebraic types (or something very close).,>,> The Fantasy Land spec codifies a standard for different types within the context of Javascript. Many libraries implement the spec, and the community is constantly growing.,> ,> If you have never heard of Fantasy Land and it sounds interesting to you, I've written a post that explains the benefits. ,> The post is written without the assumption that the reader is interested in functional programming.,>,> You can read it here: The Perfect API,,I've seen lots of interest in supporting Fantasy Land in mainstream libraries. I've seen activity on twitter, likes / hearts on github issues, people messaging me about fantasy land on gitter, google analytics on blog posts etc.,,At the time of writing, supporting Fantasy Land in Lodash is the 2nd most popular feature request sorted by thumbs up and the most requested feature when sorted by hearts,,The Front End Virtual DOM framework, Mithril is including Fanstasy Land compatible streams in its upcoming 1.0 release.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/the-power-is-yours", "title": "Fantasy Land: The Power is Yours", "date_modified": "2016-10-24T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/the-perfect-api", "content_html": "

,Imagine for a second that everything had the same interface. Everything.,,That interface would need to support asynchronous and lazy values, so it clearly needs to use functions.,,The interface would need to handle errors, but because they may come lazily, they will also require functions.,,We'd need a way to transform values (functions).,And a way to combine separate values together to create new values (functions).,,If this API is going to handle every situation, its surface area can't be used conditionally.,E.g. we don't use certain parts for certain problem domains.,Every part must be useful for every problem domain.,,It sounds like some kind of magical fantasy land - surely such a thing is not possible.,But let's try and create one anyway just to underscore how impractical we are.,,So our perfect API needs to support:,,- Creation

\n

Continued...

\n", "url": "https://james-forbes.com/posts/the-perfect-api", "title": "The Perfect API", "date_modified": "2016-05-13T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/splash-of-paint", "content_html": "

,import Slider from './slider.astro',import Toggle from './toggle.astro',,I recently ported this blog to Astro to test it out. The main reason I did that was to see if I start to focus on making the site better and writing more often instead of code golfing with generator functions.,,And today, I surprisingly did exactly that. I gave the entire site a new splash of paint.,,### Design,,The previous design was deliberately austere. I didn't have the time to put a lot of energy into it so I just needed something legible. But it was also super boring and flat. I also feel like in my "online persona" I have boxed myself in a little bit. I don't like to hurt people's feelings and so I'm pretty diplomatic online, I also hesitate to get too political or even go into just areas of interest that might bore my primarily programmer followers. But at this point in my life, I don't care. I'd rather a little zest and colour and talk about whatever I want. It might alienate some people, but conversely it might do the opposite.,,#### Colour forward,,So for this design I wanted it to be colour forward. In the header I've added some Emoji, I blew up the site logo and tilted it a bit with some glow. I've skewed the header BG (you won't see this on mobile). I've got asymmetric border radiuses. I want whoever lands on the page to get the impression they might read or discover something unexpected, but also I want to inspire myself to not be so serious and professional all the time.,,I wanted the background colour to not be grey, or white, or black. But I was concerned making the background color variable would impact legibility. So I've used a linear gradient that gets close to black pretty quickly.,,```css,linear-gradient(hsl(var(--hue), 100%, 9%), 8%, hsl(var(--hue), 100%, 3%))

\n

Continued...

\n", "url": "https://james-forbes.com/posts/splash-of-paint", "title": "Splash of paint", "date_modified": "2024-10-07T06:18:30.318Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/selfcurrying", "content_html": "

,Manually specifying the behaviour of your function given the nature of its received arguments.,,js,function distance(a, b){, if(!a) return distance, if(!b) return distance.bind(null, a), var dx = b.x - a.x, var dy = b.y - a.y,, return Math.sqrt( dx * dx + dy * dy ),},,[{x:0, y: 4}].map( distance({x:3, y:0}) ) //=> [5],,distance({x:3, y:0}, {x:0, y: 4}) //=> 5,,distance() //=> function distance(){ ... },,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/selfcurrying", "title": "Self currying function", "date_modified": "2015-06-08T01:38:58.538Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/refactoring-with-arrays", "content_html": "

,Recently, I posted a snippet of code on Twitter. The snippet was mostly received well. But there were a few people questioning the readability of a pattern I was using.,,I've introduced this pattern before in another post here, but that was in the abstract. I use this pattern so often I thought I'd take you all on a tour through a "real world" refactoring as a demonstration of its utility.,,I don't always use this pattern, there are situations where I would write a standard ternary. But when I don't trust the data I'm working with, I think it's beneficial to use an array context to represent the lack of safety and trust. This is a common pattern in many mainstream languages now. In Java there is a language level Option type. In almost all FP languages we can find Option, Result, Maybe and other aliases.,,Placing unsafe data in a separate context allows us to declare what we'd like to happen without necessarily having direct access to the value. Having indirect access prevents us from accidentally treating untrusted data as trusted.,,In Javascript itself we see this all the time with Promise. Each .then call is not immediately run, the value has not arrived yet, and may never arrive. But the indirect access allows us to declare what we'd like to happen upfront.,,#### The Example,,A lot of edge cases pop up when formatting numbers. The posted example was an x value that could be nullable, undefined, Infinity, NaN, -Infinity, 0. It's very rare to only run a simple .toFixed(2). We might want to extract the sign, transform the decimal and the whole numbers separately. Do we want to comma separate groupings of magnitude, summarise at certain points? We may have varying responses for varying edge cases. It doesn't help if we accidentally divide by zero either!,,Small details appear that only make sense in certain contexts. Notice when formatting negative dollars, the - symbol is before the $ currency symbol. ,,,-$4.00,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/refactoring-with-arrays", "title": "Refactoring with Arrays", "date_modified": "2019-01-20T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/reduce", "content_html": "

,First off! Let me just say, I am not an expert at functional programming (or any kind of programming for that matter). But perhaps my level of understanding will make this topic more interesting to those that are not ivory tower functional space wizards.,,If you want to read someone who knows what they are talking about, you can do so here,,A bold claim,------------,,Programming has many methodologies and philosophies and space wizardry, but at the end of the day, all we are ever doing is editing the values of some data.,,And if your data happens to be in an Array like data structure, you will only ever need one tool to perform these tasks.,,That tool is reduce.,,What is reduce.,--------------,,Reduce is a function that lets you remove a lot of repetive fluff that occurs in nearly every algorithm. There is usually some array of results, or final value we want to boil down to. There is a loop, which lets us do something to that data every time. And then there is the actual something that we are doing.,,Reduce lets you focus on the something and not on the ceremony.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/reduce", "title": "Reduce: the genome of algorithms.", "date_modified": "2015-01-19T06:27:37.705Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/redefining-filter", "content_html": "

,Have you ever written code like this before?,,js,var list = [],for(var i = 0; i < somethingElse.length; i++ ){, if( someCondition ){, list.push( somethingElse[i] ), },},,,I've seen this pattern come up in a lot of code I review. We can replace this custom logic with a standard template: filter,,js,var list = somethingElse.filter( () => someCondition ),,,For some readers this might be familiar territory. You may have already internalized that you can replace this particular pattern with filter. But let's disect it so we can use filter in more interesting ways in a moment.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/redefining-filter", "title": "Redefining Filter", "date_modified": "2017-01-25T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/ramdascrape", "content_html": "

,General Practicality of Ramda and Functional Techniques,-------------------------------------------------------,,Ramda is a functional Javascript utility library. It is extremely useful for reducing complexity of involved tasks by allowing for composition of small functions into larger ones. Ramda encourages a flow of data instead of storing global state for later use.,,There are many demonstrations of Ramda, but most of them are very pie in the sky, and don't use actual data. This demonstration will ensure our data is real, we will scrape it from the internet!,,At a later stage, I'd like to take the output data from this exercise, as input for another demonstration of Ramda's prowess at data processing.,,Presidents from Wikipedia,--------------------------,,We are going to use Ramda, Promise, Cheerio and Request in nodejs to parse Wikipedia into an array of data on United States presidents.,,I've purposely picked scraping instead of consuming an API, because it tends to get messy. You are making multiple asynchronous requests, and you have callbacks, and you have to parse data, and aggregate it. ,,When this turns out to be 50 lines of easy to read and edit Javascript, I will have succeeded in my mission.,,Setting up the Project

\n

Continued...

\n", "url": "https://james-forbes.com/posts/ramdascrape", "title": "A practical Ramda example: Scraping", "date_modified": "2015-01-08T02:38:59.976Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/power-of-m-prop", "content_html": "

,> Please be aware this post was written when Mithril 0.2x was state of the art.,> Mithril 1.0 has built in support for streams and closure components; and enables writing in a declarative fashion.,> Many of the points I make here are still valid, but need to be read in the context of the mithril 0.2x API.,> The specific code samples and techniques used do not apply if you are using Mithril 1.0,>,> I'll leave this article here for posterity, and when I've got more experience with 1.0 I'll post a follow up.,> In the interim please feel free to ask questions in the mithril chatroom.,> ,> Happy Coding - James,,Recently I've been working on a large interactive web app as part of a business I am involved in.,,We have been using Mithril to build all our ui's to date, and it has proven itself,to be a wonderful framework for building stable predictable user interfaces.,,One of Mithril's greatest strengths is its small API surface. What was, and was not included, was for good reason.,,The included API surface is often slightly unintuitive at first, but solves common problems more elegantly than other,frameworks I've used.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/power-of-m-prop", "title": "The power of m.prop", "date_modified": "2016-01-08T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/philosophies-vs-frameworks", "content_html": "

,I've recently been quite excited by the thought of creating philosophies as opposed to libraries or frameworks. ,,There have recently been many libraries released that are not really heavy on source control, but have reams of documentation.,And I think that is a more sustainable approach to software.,,CycleJS is a new approach to the Model View Controller pattern. in CycleJS you build your application as a single function that accepts a stream of responses from the user, and you reply with a stream of requests for further input.,There is a brilliant talk on CycleJS, by the creator Andre Staltz called The User As A Function.,,Perhaps the most interesting part about CycleJS is that it is a very small abstraction built on top of two other libraries. CycleJS is more philosophy than source code. It is a way to combine other abstractions.,,Mithril is another MVC framework that is light on source code and heavy on philosophy. Mithril is only 12kb gzipped but it has countless articles of well written prose. It's design is like a martial art. It provides minimal but powerful tools that transforms the immense struggle of developing user interface code into an effortless expression, perhaps even an artform.,,Mithril has a small but passionate community that all seem to appreciate that Mithril is more practice than source code. Many in the community support future releases removing features instead of adding them. This approach seems bizarre until you stop thinking of a framework as a product and instead think of it as refinement of a concept.,,I'm excited by this shift. Instead of deploying source code, we are deploying abstractions, concepts.,The source code is just a road to take us to an idea.,,Ramda is a collection of utility functions that focuses on clarity, simplicity and maximum composition. The library itself has grown substantially, but the real Ramda isn't source code at all, it's a philosophy. The philosophy is to make building blocks that only do one thing in one way, but make it simple to combine these blocks to create new functionality.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/philosophies-vs-frameworks", "title": "Philosophies. Not Frameworks.", "date_modified": "2015-06-08T01:38:58.538Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/node-scripting-tips", "content_html": "

,Using node.js as a scripting language.,--------------------------------------,,node isn't the first language people think of for day to day scripting tasks. Usually python is recommended, maybe bash. I think there's some good reasons for this notion - node is async by default which can make simple operations seem convoluted or complex. But it's not bad, it's just different. So today I want to share some of the tricks I've learned to make the most of JS as a general purpose scripting tool.,,## Node is a facilitator.,,Node is very good at letting other tools do the heavy lifting. It's designed to wait efficiently in the background until some task is done and then fire off the next task. And it's able to handle many parallel queues of work. Node streams allow you to fire off thousands of requests and yet only process data or request information when it's logical. Node's built in modules and ecosystem is by default - async. That means while you're talking to a DB, you can also be reading a file. Turns out that's a very nice quality for writing scripts that aren't painfully slow.,,Put another way - node is good at efficiently organizing and managing external resources. Its strength is in handing off work to external services, native binaries, databases etc and because it is "async all the way down" you are sort of forced to write fast code.,,## Python,,But being async is also what makes people reach for python. Python is a one stop shop, it has a giant standard library, massive community (almost rivaling JS') and there's no async to think about (unless if you reach for it). Scripts in python are linear, simple and obvious - first this thing finishes, then the next thing starts and so on.,,I think python is a fine tool for scripting, but if you've already got a big JS project it's nice to not have 1 language for your application and another for your scripts. I've also found the moment I want to use a library in python I end up spending hours configuring things and reading blogs because pypy didn't work, or because libraries are shared globally.,,Some say, "use docker!" and sure, that works. But now you've got two problems.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/node-scripting-tips", "title": "Node scripting: Tips and tricks", "date_modified": "2020-02-02T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/noclasses", "content_html": "

,I've been using LeafletJS a lot while writing the secret project I mentioned earlier. And because Leaflet insists to encapsulate data in its homemade class system, I had to spend a lot of time and energy hacking Leaflet to let me draw to a map without handing it any of my data.,,Data is not the focus of Leaflet. Leaflet's focus is nice, simple, maps embedded into webpages. I wanted Backbone to manage my data because it is an event system designed for the express purpose of handling changing state. Leaflet is a mapping library, but for some reason it is also a data conversion utility and an OOP library.,,There are libraries I make use of when handling geodata. But it is extremely frustrating to compose functionality between these libraries, because these functions do not return raw data, they return data wrapped by a pseudo class, and I can't reason about the behaviour of that return value as easily as I can a pure function.,There were times where I had no choice but to use L.Point to do some geospatial conversions.,,Here is the add function in L.Point at the time of writing,,```javascript, // non-destructive, returns a new point,\tadd: function (point) {,\t\treturn this.clone()._add(L.point(point));,\t},,,\t// destructive, used directly for performance in situations where it's safe to modify existing point,\t_add: function (point) {,\t\tthis.x += point.x;,\t\tthis.y += point.y;

\n

Continued...

\n", "url": "https://james-forbes.com/posts/noclasses", "title": "A better LeafletJS", "date_modified": "2014-10-29T11:12:06.740Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/new-library-superhistory", "content_html": "

,I've recently been pretty active creating little micro libs as I wanted to have some small self contained, well tested atoms that I could stick together to give me confidence in a larger system.,,So there'll probably be a series of posts over the next few weeks walking through some of these libraries.,,The first is superhistory.,,### Why?,,superhistory came about when I was working on nesting routers. There's not a lot you have to do when nesting routers, but its important each piece is absolutely rock solid as there is a cyclic dependency ,,,mermaid,graph LR, A[State Update]-->B[Browser History Update], B[Browser History Update]-->A[State Update], ,,,If your path normalization is wrong you can end up with an infinte loop.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/new-library-superhistory", "title": "New library: superhistory", "date_modified": "2024-01-01T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/mithril-rewrite-streams", "content_html": "

,> I don't have real time data in my app, so do I need streams?,,Streams are about streamlining real time user interactions as data.,While you could use it for web socket server data. That is not the focus.,,> Aren't promises enough?,,Promises are not a suitable data structure / abstraction for handling user input,because Promises represent a single value, while user input is multiple (possibly infinite) ,values over time.,,> I don't use m.prop currently? Why would I use it now?,,m.prop as it stands is useful for 2 things, passing references cleanly, and making event callbacks simpler.,It makes sense to avoid that extra layer of abstraction if you do not value the benefits that abstraction provides.,,But now that props are streams, we can base our ,,> Are observables just some sugar on top of the Observer pattern?

\n

Continued...

\n", "url": "https://james-forbes.com/posts/mithril-rewrite-streams", "title": "Stream Misconceptions", "date_modified": "2016-06-23T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/lambda-functions-microservices-and-you", "content_html": "

,Ye olde Express,---------------,,A typical approach to writing an API or service in NodeJS would be to use http://expressjs.com/.,Express let's you define functions that respond to endpoints you define. Express manages converting HTTP requests into,particular routes. It does many other things like oauth middleware, JSON parsing etc but its core functionality is ,routing the HTTP layer into a series of endpoint actions.,,You can deploy an Express app anywhere where a HTTP port is open and NodeJS is running.,,Some common 3rd party products for hosting include:,,- Heroku,- Google App Engine,- Amazon Elastic Compute Cloud,- Microsoft Azure,- Zeit now,,All these strategies involve running a server for you that simply directs HTTP traffic to your Express app.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/lambda-functions-microservices-and-you", "title": "Lambda Functions, Microservices and You", "date_modified": "2016-12-28T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/intro-to-streams", "content_html": "

,Streams go by many names and representations. You might hear terms like Observables, Facts, Channels, Behaviours (and even Iterators / Generators). From conversations I've had with many developers, it seems the fundamental power in the abstraction is often replaced with an obsession with the particular implementation instead of the reason for the implementation.,,In this post, we are going to rectify that. I don't want to address the specific problems I see in the larger discourse surrounding streams - but I am going to request that you approach this post with a clean slate. If you have experience with a stream library and its particular pedagogy and vocabulary - please put that to one side for the duration of this post.,,By the end of this post, you will be able to:,,- See how streams elegantly manage complex state synchronization. ,- See how these concepts apply in innumerable common contexts. ,- Understand how streams prevent us from introducing a large swath of common bugs. ,- Be able to do this without having to learn dozens of new concepts and jargon.,,The problem with names,----------------------,,Before we seek to understand streams, we must understand the problem that they solve.,,js,var age = 2,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/intro-to-streams", "title": "Intro to Streams", "date_modified": "2017-11-04T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/intro-to-monads", "content_html": "

,What isn't a Monad? And why doesn't it matter?,-----------------------------------------------,,> Some people have said to me they were deeply disappointed that this wasn't a real intro to Monads. I'm sorry for misleading you. I've added some links to some actually useful resources at the end of this post.,,Look. Nobody knows what a Monad is. Really.,,Why do you think Haskell's package manager is called Cabal? It's because there's a cabal of computer scientists making up words and seeing if we actually read their papers or instead just blindly believe everything Bartosz Milewski blogs and follows along (spoiler: that's what we do.),,People don't actually read FP papers. People who think they understand FP papers are people positive that they know the names of constellations. They don't. They just made it up and no-one ever corrected them. Yes, I'm Sirius, people who read FP papers are people who read tea leaves. There's no punch line there, that's just something I noticed.,,What we should be discussing is what a Monad isn't. Because learning what a Monad is, is a side effect. You might learn what it is and then do stuff. And Monad's are about never doing things. So explaining what one is, would be a proof by contradiction...,,See! You didn't even read that. Let's see what Brian Lonsdorf and Hardy Jones says on the topic:,,\tHardy: "Hi!",\t,\tBrian: "Hi!",

\n

Continued...

\n", "url": "https://james-forbes.com/posts/intro-to-monads", "title": "Intro to Monads", "date_modified": "2017-07-20T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/how-to-talk-to-a-computer", "content_html": "

,How to work within the REPL,---------------------------,,Like most worthwhile things in programming, the REPL is a useful, powerful tool - with a terrible name.,But once the unfamiliarity wears off, the name becomes endearing.,,> REPL means Read - Eval - Print - Loop, which is exactly how a REPL operates!,,We write programs with the intention of running them. The traditional usage is writing some code, saving it to a file,and executing it against some binary. If it's a compiled language that binary will emit some executable file, and if it is a,strongly typed language, you'll get some errors when attempting to compile if your types do not line up.,,These steps can be considered friction; unnecessary separation between writing and executing; human and computer.,,The REPL on the otherhand blurs the line between writing and executing. Instead of preparing all statements and expressions ahead of time in order to get a final computation, the repl waits for your input after each evaluation.,It's more like a conversation with the computer, where you are an active participant.,,By reducing latency between program and programmer we can often iterate on our design, find, and solve problems more readily.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/how-to-talk-to-a-computer", "title": "How to talk to a computer", "date_modified": "2016-09-11T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/how-i-use-mithril", "content_html": "

,> Please be aware this post was written when Mithril 0.2x was state of the art.,> Mithril 1.0 has built in support for streams and closure components; and enables writing in a declarative fashion.,> Many of the points I make here are still valid, but need to be read in the context of the mithril 0.2x API.,> The specific code samples and techniques used do not apply if you are using Mithril 1.0,>,> I'll leave this article here for posterity, and when I've got more experience with 1.0 I'll post a follow up.,> In the interim please feel free to ask questions in the mithril chatroom.,> ,> Happy Coding - James,,Mithril is a tiny library for writing interactive web applications.,It's so small it may seem difficult to know where to start.,,Mithril is used by large in production apps, but its footprint is ~8kb. Yes it's website could use a bit of spit and polish,but it truly is the best MVC framework we have in Javascript right now.,,I've previously written about other aspects of mithril, like m.prop and how cleanly,it solves a lot of common problems I've experienced in other frameworks like Backbone.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/how-i-use-mithril", "title": "How I use mithril", "date_modified": "2016-04-21T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/hooks-and-streams", "content_html": "

,Dan Abramov wrote an excellent blog post about making a declarative setInterval using React Hooks.,,Check it out here. It's a great read.,,I think Hooks are really cool, especially from a technical perspective. But they are also a bit of a leaky abstraction. If you know the rules of hooks and understand why they exist you'll likely be fine - but I hope to convince you there's a better, simpler solution.,,Hooks received a lot of criticism when first announced. I didn't want to weigh in on that initial deluge because I think a lot of it was unjustified. But now that the dust has settled and most people generally think Hooks are a good idea, I wanted to explain an alternative approach with all the same advantages and none of the caveats.,,Unfortunately simple is not easy. To get to the point where we can explain this simple alternative, we'll need to: walk through some SPA history; explore some alternative component interfaces; introduce a very small API surface for streams; and then we can compare and contrast with Dan's blog post. I am confident it is worth your time, but if at any point you feel you need to take a break - please do so.,,Hooks usage is beholden to a set of rules because it's ultimately a very clever illusion. Hooks make it seem like you're accessing persistent state entirely within the scope of a function call - but that's not really possible without some other background mechanics. In React's case, they infer which state belongs to which function call by counting invocations. It's more nuanced and complicated than that, but ultimately it's still inference.,,By the end of this post I'll have hopefully demonstrated to you that inference isn't required. But before we can even discuss alternatives we need to see Hooks with fresh eyes and within their historic context.,,> 💡 SPA is short for Single Page App. It refers to applications that do not require a page refresh to navigate to another page in a web application. I'm using that specific terminology because SPA's have a very unique and interesting history that is separate from UI programming generally. Statically linked HTML files and 100% server rendered pages are a very different problem domain. React can be used in these other contexts, but I'm not speaking to that subset of usage.,,#### A short history revision,,##### The V in MVC

\n

Continued...

\n", "url": "https://james-forbes.com/posts/hooks-and-streams", "title": "Hooks and Streams", "date_modified": "2020-02-22T01:03:26.420Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/hardcoding", "content_html": "

,Better than generic coding,--------------------------,,The one thing I have struggled most with over the years, is deprogramming,all the Java nonsense that was stuffed into my head at University.,,Just when I think I have unlearned what I have learned, I find myself reading,recent code and getting very angry at myself for complicating a simple end goal,by trying to save myself work in the future.,,So as an affirmation of the clarity that can be found by hard coding. Let's,do a code review of this website.,,### Sidebar,,I have just rewritten the equivalent functionality of this website in 40 mins. It,is now much faster, and easier to edit. I removed all the MVC nonsense,and instead have a few functions that return very specific HTML strings for my,very specific needs.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/hardcoding", "title": "Hardcoding is great", "date_modified": "2015-01-31T03:37:30.456Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/grokdash", "content_html": "

,Lodash and UnderscoreJS have become ubiquitous in Javascript projects (and other languages too!).,,But beyond, map and filter what wonders lie beneath the humble _? I am here to shed some light on many of the functions found in Lodash. And explain when they can be useful.,,If you feel very confident with Underscore's API, then this article may not be for you. Perhaps you can help identify any mistakes and make suggestions.,,Real Problems,-------------,,To demonstrate the usefulness of these libraries, I'll try to make each example's scenario as realistic as possible - to ease the transition from learning to practical use.,,,#### _.defer: call a function, after all the other functions have finished being called.,,,```javascript,_.defer(function(){, console.log(1),})

\n

Continued...

\n", "url": "https://james-forbes.com/posts/grokdash", "title": "Grokking Lodash", "date_modified": "2014-11-22T08:56:20.959Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/backbone-to-mithril", "content_html": "

,> Please be aware this post was written when Mithril 0.2x was state of the art.,> Mithril 1.0 has built in support for streams and closure components; and enables writing in a declarative fashion.,> Many of the points I make here are still valid, but need to be read in the context of the mithril 0.2x API.,> The specific code samples and techniques used do not apply if you are using Mithril 1.0,>,> I'll leave this article here for posterity, and when I've got more experience with 1.0 I'll post a follow up.,> In the interim please feel free to ask questions in the mithril chatroom.,> ,> Happy Coding - James,,,\"\",,When I first started eyeing off mithril, I found it hard to imagine adpating my existing knowledge of JS app development ,to this new framework. There is a great article Leo Horie wrote comparing ,mithril to other major JS Frameworks but it was written as if the reader had,already bought into mithril's philosophies.,,The framework I had the most experience with, before trying mithril, was Backbone. So instead of saying why Mithril is better

\n

Continued...

\n", "url": "https://james-forbes.com/posts/backbone-to-mithril", "title": "The road from Backbone to Mithril", "date_modified": "2016-05-02T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/astro", "content_html": "

,I often use my own blog as a way to try out ideas and frameworks. Recently someone in the mithril chat mentioned they liked Astro for SSG. They had made a mithril package for astro's "Framework Island" feature.,,My blog has always been hand rolled. It's not very hard to load some markdown files from disk and convert them into HTML so I never really saw the attraction. But I also find myself feeling pretty burnt out creating "contentful" pages for work. I thought I'd give it a go. It's the little things that add up. E.g. even for my simple blog I had to handle syntax highlighting, rss feeds, mermaid charts. And there was more I wanted to do but just never found the motivation.,,Its easy to fall into analysis paralysis, or to get excited and try some new technical idea on each little side project. That all eats up time that should probably be spent elsewhere. So maybe using something specifically designed for that task could be beneficial.,,At the time of writing, this site is now powered by Astro. I'll use this post to document the experience and the set up I landed on.,,In short, I like it, I would even recommend it for many use cases. For me personally I'm not sure if I'll keep using it. But I think the real measure of success will be if I start writing more instead of tinkering with tech stacks. Time will tell.,,### The DX is good,,First of all, the developer experience is excellent. I used npm create astro and followed the wizard and was up and running quickly. The documentation is comprehensive and easy to follow. The VSCode extension works well. Writing Astro components doesn't feel foreign, and a lot of the decisions re: the Astro component programming model are interesting and show a lot of thought has gone into what Astro's roles and responsibilities are and where to draw that line.,,At other times though it feels like Astro is trying to have an answer for every question. I think it could benefit from a smaller scope with some recipes / patterns to solve those other areas.,,I get into it more as we go on.,,### The Astro component model

\n

Continued...

\n", "url": "https://james-forbes.com/posts/astro", "title": "Trying out Astro", "date_modified": "2024-10-06T01:48:09.233Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/alternative-to-npm-scripts", "content_html": "

,> This proposal works best for applications where the set of people that build your project are developers, ci, etc. For node libraries, there are a different set of constraints. This proposal can still apply for a subset of tasks, but only when you know the environment of the installer (which for node libraries, you can't).,,npm scripts are great. npm's scoping of local binaries to a project is fantastic for deterministic builds that don't rely on ambient environment binaries.,,But they aren't perfect. There are work arounds for every problem, but they are not satisfactory, and yet (prior to thinking of this new approach) I still prefer npm scripts to any other approach to builds that I've seen or used.,,So what is great about npm scripts?,,- pre/post hooks are a simple low tech alternative to dependency tracking and allows you to ensure code runs before a publish or before an install.,- adding local node_modules/.bin binaries to the path allows us to treat local binaries as if they are accessible globally leading to (hopefully) more deterministic build scripts,,And what are the problems with npm scripts?,,- No comments or line breaks in JSON strings leads to hard to read commands,- On Windows the shell is enforced to be cmd.exe even if bash (native or git bash) is present. This leads to unnecessary friction for windows devs contributing to node projects (which should be os independent like node itself),- Composition of scripts is verbose because they must be prefixed by npm run, there are libraries that mitigate this but they have their own problems.,- Shell incompatibilities between default shells on various systems including unix like systems leads to subtle problems for contributors and in CI environments.,,We want to keep the good, and lose the bad. There will be trade offs but I think with a few conventions we can reach a very nice compromise.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/alternative-to-npm-scripts", "title": "bash run: an alternative to npm scripts", "date_modified": "2017-11-09T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/activity-pub", "content_html": "

,### ActivityPub,,- https://hammyhavoc.com/setting-up-my-blog-within-the-fediverse-via-activitypub/,- https://docs.joinmastodon.org/spec/webfinger/,- https://www.w3.org/TR/activitypub/,- https://en.wikipedia.org/wiki/ActivityPub,- https://atproto.com/guides/applications,,### Spotify,,- https://developer.spotify.com/documentation/web-api,,### WYSIWIG,,- https://github.com/Ionaru/easy-markdown-editor

\n

Continued...

\n", "url": "https://james-forbes.com/posts/activity-pub", "title": "Blog Research", "date_modified": "2024-10-07T13:25:59.667Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/notumblr", "content_html": "

,I've got the basics working. Markdown files are read via the github API and loaded onto the page.,I've avoided using a Framework like Backbone for the moment, and just used plain old functions.,,I'm using my templating library temple. It is definitely succinct, but,there isn't much html yet, so it hasn't show itself much.,,I haven't styled the site yet at all. I might try sass for a learning experience, but I'm not sure I want to introduce,a dependency. I might just stick to CSS for now.,,I decided not to use Tumblr for now because I am so happy with the GitHub API. That means, for now, no-one can,follow my blog, but I will have a link to my twitter and github, so if someone wants to know when I post something, they can.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/notumblr", "title": "No Tumblr, But all is well", "date_modified": "2014-08-03T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/hostingghpages", "content_html": "

,After much tinkering with DNS settings I finally got this project to be served via github pages.,,A bonus, all my other github repositories that use gh-pages (which is most of them) are being served at the same address.,,So my game Provider, is being served at http://james-forbes.com/provider automagically.,,Another reason for this is to check if my date stamps are working correctly.,,I'm thinking of adding a comment section with some relevance validation protection too. I've got a prototype and I'm hoping I can integrate it with Disqus. If so I might make it a separate library for others to use.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/hostingghpages", "title": "Custom Domain Name hosting via Github Pages", "date_modified": "2014-11-04T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/googleglass", "content_html": "

,It was the blurst of times.,---------------------------,,So, I know nothing about Google Glass. I am not excited about it. I am not going to buy one. And I thought this was funny.,,But it is interesting to me. Glass is not a consumer device, it is a hacker's device. Google glass subverts the most common trope of computer programmers. That they are anti-social, that they "need to go out more".,,Suddenly you'll have hackers, walking around, scraping the street instead of the web (Actually, that is a false dichotomy, the web will never have been so inescapable and omnipresent).,,The kind of data, and patterns that will be identified is hard to fathom.,,Like all fringe technology, there is a lot to be excited, and scared about.,,Glass will be great for documentarians, home movies, historical records, and lots of other stuff.,,But what most interests me. Combined with streaming services, Google Glass will create a new kind of embedded media broadcast. Citizens, on the sidelines of conflict, unrest and oppression will be able to share their eyes with billions of people instantly. I am excited that the audience of these broadcasts may evaporate silent crimes.,,And I know Google sees that as the future. And that is why they bought Twitch.tv. And that is why I am also afraid. I am scared about those recordings sitting on Google's servers, being automatically shared with ad partners. I am afraid that society will become so accepting of being filmed by their peers, that they will accept and expect to be filmed by their governments.,

\n

Continued...

\n", "url": "https://james-forbes.com/posts/googleglass", "title": "Google Glass", "date_modified": "2014-08-03T23:52:20.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/datestamps", "content_html": "

,Date stamps are working. I tried using John Resig's pretty date script,, which is pretty nice, but is only suited for twitter-like situations, because the longest description it uses is 'n weeks ago'.,,So I googled some more and found moment.js, which is mind blowingly good. Reminds me of Python's date support.,,I am getting the date stamps from file commits for a particular blog post. The post date is the earliest commit, and the updated date is the most recent commit.,,I'd like to have a wordpress style archive widget on the left. For now I am just listing by title.,,I am suprised how quick that has come together.

\n

Continued...

\n", "url": "https://james-forbes.com/posts/datestamps", "title": "Pulling Datestamps from commits and formatting them with moment.js", "date_modified": "2014-08-03T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/curryinghurrying", "content_html": "

,For the sake of this discussion, all functions are now aeroplanes.,,js,function Aeroplane(){,,},,,And each Aeroplane can take many passengers,,```js,function Aeroplane(, passenger1, , passenger2, , passenger3,){, return "Taking off! With: ", + ([]).slice.apply(, arguments

\n

Continued...

\n", "url": "https://james-forbes.com/posts/curryinghurrying", "title": "Currying vs Hurrying", "date_modified": "2014-11-12T11:18:49.210Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } }, { "id": "https://james-forbes.com/posts/blogproject", "content_html": "

,I want to test if I can integrate a local markdown file,with a tumblr blog.,,Why?,----,,I like to have diffs on my posts. But also only like to have a single,source of truth. I don't want to have to manually keep my blog and,the repo in sync.,,I also really like tumblr as a platform. I like how accessible tumblr's customization,is, and I like there is a very high technical ceiling of possibilities that they didn't take,away from the users.,,You can make your page do whatever you want, inject any JS or CSS and even remove the tumblr branding.,,I've got a few projects that piggy back tumblr to great effect.,,Zoe Appleseed's website is built on top of tumblr's API. We built

\n

Continued...

\n", "url": "https://james-forbes.com/posts/blogproject", "title": "Blog Project", "date_modified": "2018-09-26T00:00:00.000Z", "author": { "name": "James Forbes", "url": "https://github.com/JAForbes" } } ] }