Skip to content

Instantly share code, notes, and snippets.

@gemmadlou
Last active September 27, 2016 16:24
Show Gist options
  • Save gemmadlou/57cdbb8265a5024dfc0400ccd8d045fc to your computer and use it in GitHub Desktop.
Save gemmadlou/57cdbb8265a5024dfc0400ccd8d045fc to your computer and use it in GitHub Desktop.
Random Notes - Functional Programming Style

Random Notes - Functional Programming Style

Sunday 12 June 2016

Note: instead of writing a blog that's well structured and useful, I'm just throwing down notes, pieces of information and code that will help me to build a little application that will (possibly) get real world use. If I achieve it, maybe I might write something a little more helpful. However, you may find this little gist/blog nice to read for your project.

So here's the first bit of code (in at the deep end):

Dependencies include:

  • Rambda (for flowery functional functions like curry and compose)

  • Bluebird (for promises)

     // html
     <div id="app">
     App
     <!-- Dynamic page -->
     </div>	
     <div id="home">Home</div>
     <div id="login">Login</div>
     ...etc
    

// js
var router = function(hash) {
  var routes = {
    '': 'home',
    '#': 'home',
    '#login': 'login',
    '#register': 'register',
    '#processing': 'processing'
  }
  return routes[hash] || null;
}
'

var viewTemplate = function(id) {
  var html = document.getElementById(id).innerHTML;
  return html;
}

var setHTML = R.curry(function(elementId, html) {
  document.getElementById(elementId).innerHTML = html;
});
 
window.Page = (R.compose(setHTML('app'), viewTemplate, router));

// Start app with homepage (route)
Page('');

The above employs declarative style code. We ask for the "what", not the how. viewTemplate is a impure function as it relies on a dependency that we are not accounting for, document.getElementByID. setHTML doesn't return anything so it is impure too. However, the route is fully pure The window.Page function takes the router parameter, plugs that result into the view template, which plugs the html into the setHTML function which generates the new page.

Here's a working example: https://jsfiddle.net/gemmadlou/xg9e92ss/18/

If you're not familiar with functional programming - like myself, two functions may not be so understandable in the example above.

  • curry
  • compose

Don't worry, I'm still going through this wonderful book which will explain to you everything you need: https://drboolean.gitbooks.io/mostly-adequate-guide

The next steps:

  • Fake user login for now - I can't be bothered to work with a federated signin like Google or Facebook yet. I just want to spend time on domain specific logic.
  • Allow user to see the status of the process of the application if they are under review
    • The only things they can see in the user dashboard are:
      • Their profile
      • Their status
      • They cannot purchase any tickets
  • Then test another userflow, that when they login being they've been approved, they can now see the user full user dashboard
    • Their profile
    • Their statusf
    • Buy ticket page

Cheating with logged in user flow

Okay. So I created a function that basically changes views without logging users in. But how do I log a user in and then redirect them to a page?

So the next basic step is:

  • Log in user
  • Redirect user to appropriate page (preferably the profile page)

Ooooh - another resource: https://jcouyang.gitbooks.io/functional-javascript/content/en/higher_order_function/compose_function.html

https://templecoding.com/blog/2016/04/13/functional-javascript-introduction-and-currying/

The ultimate resource http://www.fse.guru/how-do-i-learn-functional-programming-in-javascript-linkpost

Headache! http://eamodeorubio.github.io/tamingasync/#/36 - this might save me


Monday 13 June 2016

A little tid bit to capture onload events as a deferred promise:

// using bluebird.js
function domReady() {
  return new Promise(function(resolve) {
  	var state = document.readyState;
    if (state === "interactive" || state === "complete") return resolve('ready');
    document.addEventListener("DOMContentLoaded", resolve);
  });
}
domReady().then(function(res) {
  //do something to dom
});

With promises it's awesome you can do the above. But I'm still not a fan of the potential branching problem that comes with asynchronous code, which I've left out of the prototype to keep everything synchronous.


The app Back to the beginning:

I've already pre-empted problems with authenticating and running asynchronous code. Thus event sourcing and DDD.

The domain has to be the User. Their state will look like this:

// This user can buy more tickets
var user = {
	id: 1,
	loggedIn: false,
	approved: {
		status: false
	},
	ticketsPurchased: [
		{num: 1, paid: 20},
		{num: 2, paid: 20},
		{num: 3, paid: 20}
	]
}

// This user cannot buy tickets
var user2 = {
	id: 2,
	loggedIn: false,
	approved: {
		status: true,
		by: 'Johnny Smith'
	},
	ticketsPurchased: []
}

However, I have questions:

  1. Does it matter that the user.approved.status === true, because when they attempt to purchase tickets, we have to authorise their purchase on a server/lambda somewhere. Do we even bother saving authentication state? I guess only to show stuff on the UI.
  2. What about the fact that the state of user and user2 shows loggedIn as true or false. Whether they're logged in or not is irrelevant to the application as it's based on the user token which if it's Google+, is calculated on the load of their API. If the token is accepted, they're logged in. If not, they're not. Do I need to map this, or can I just authenticate without checking user state?

... some more readings:

What's the first event? http://programmers.stackexchange.com/questions/232774/how-add-create-commands-should-be-handled-in-cqrs-event-sourcing-architecture#answer-288563

Authorising events: http://blog.zilverline.com/2013/01/09/simple-event-sourcing-users-authentication-authorization-part-6/

Basic event store implementation http://blog.arkency.com/2015/03/your-solid-tool-for-event-sourcing-eventstore-examples/

A case for Redux vs tradditional event sourcing reduxjs/redux#891

Tasks

What I want the user to do:

  1. Register user and save to a database
  2. Login user
  3. Display profile page
  4. View profile page 5. [ ] Shows tickets purchased 6. [ ] Status of the current membership 7. [ ] A link to buy more tickets (if they're approved)

Register user and save to a database and going Reactive with RX JS

Tuesday 14 June 2016

A book on reactive programming with RxJS.

http://xgrommx.github.io/rx-book/content/guidelines/introduction/index.html

Notes from the book so far:

What is reactive programming? Reactive programming is programming with asynchronous data streams.

And what's the functional part? On top of that, you are given an amazing toolbox of functions to combine, create and filter any of those streams. That's where the "functional" magic kicks in.

Back to our App (starting again in Plunkr)

The user 1. enters their details into a form, for now, just their name and email. It saved, validated to a database somewhere. 2. They then get redirected to their dashboard.

Here's the plunkr: https://plnkr.co/edit/2u3v3w1eETcAnVvIJ1QO?p=preview

Friday 17 June 2016

A great resource on RXJS...thankfully:

https://miguelmota.com/blog/getting-started-with-rxjs/

Having fun with manipulating a cartesian product: http://jsbin.com/buqubu/edit?js,console

Satursday 18 June 2016

Finally, something that's as functional as I can get it by myself

  • Using react
  • RxJS to map streams
  • Memoization
  • The potential for throttling

https://jsfiddle.net/gemmadlou/fez69ggg/

Funnily enough, watching cycle.js video on Egghead showed where my problem was when it came to the dom. The problem was creating an event handler to a dom element that didn't exist yet. That's okay, JSX allows onClick, onChange and-so-on event handlers in the dom. However, the RxJS standard example showed that you needed to map the dom events...

var $input = $('#input'),
    $results = $('#results');

/* Only get the value from each key up */
var keyups = Rx.Observable.fromEvent($input, 'keyup')
    .map(e => e.target.value)
    .filter(text => text.length > 2);

Just to reiterate. You can't attach a dom element that hasn't been created yet...

So I solved it by creating an event handler function which seems rather messy, inside the JSX dom, and was able to capture user intent, and then call the appropriate observable. The creator of cycle.js solved it by creating a proxy dom using new Rx.Subject(), attaching that, then replacing that dom with the real one once rendered.

I think his way is better, I'm just not smart enough to know why...yet. At least, my main concern is mapping components inside components react style...so I can follow the React routine. He however says you can have cycle.js apps within apps. You can actually have portable apps, basically little functions that you can swap in or swap out.

https://egghead.io/lessons/rxjs-generalizing-run-function-for-more-types-of-sources

Resources:

Tools

http://reactcompose.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment