Hacker Newsnew | past | comments | ask | show | jobs | submit | more benawad's commentslogin

Cool project, I love that you can search by macros. A few points:

1. Clipping recipes from different websites can be quite challenging because of the varying html structures. I recently tackled this problem and I'm curious what method you used to find recipe content within an html page? I ended up checking to see if the website followed a Recipe schema [1] and if not use a mix of heuristics to try identifying if a line of text was an ingredient. I also was considering using machine learning in there, but couldn't figure out a good way to incorporate it.

2. Is there a reason you don't include the instructions of the recipe on your website?

Awesome to see some fresh sites in this space. I built Saffron [2] which is focused on organizing your recipes into digital cookbooks.

[1] https://schema.org/Recipe

[2] https://www.mysaffronapp.com/


For this project, I used Spoonaculars API for clipping recipes. I would be very interested in creating my own, similar to what you did. That would give me more control over the process. Did you come across any open source repos when you worked on your crawler?

> Is there a reason you don't include the instructions of the recipe on your website?

Yes, when users clip recipes from another source I want to make sure that users need to navigate back to the original page to see the instructions. This is to ensure the original author gets credit for it. If a user adds a recipe themselves to the site then it will show the instructions. Here is an example of a recipe with instructions for demo purposes, https://www.feastgenius.com/recipes/everything-nice-jerk-chi....


I didn't find any good open source options


I couldn't find any info on how much saffron costs to use?


It's currently free and will stay free for those who signup now.

I'm working on adding a $5/month subscription.


It would be cool to be able to attach it to different frames. The default one looks low quality.


I recently read the book "The 22 Immutable Laws of Marketing" and it talked about how when a company adds more lines of business that long term it can have negative effects (lack of focus). Do you think Apple has over diversified?


KISS


> Key Business Question to Answer: Is the value proposition of a large encrypted file transfer service enough to drive Firefox Account relationships for non-Firefox users.

The metrics section is interesting https://github.com/mozilla/send/blob/master/docs/metrics.md


Oh interesting. Their two hypotheses (which they will test) are that Send "can drive Firefox Accounts beyond the Firefox Browser" and that it will "will provide a valuable platform to research, communicate with, and market to conscious choosers..."

It sounds like they're investigating a premium service offering targeted at privacy conscious users. (The secondary hypothesis covers "revenue" and will be tested by conducting "research tasks ... in support of premium services KPIs.")


If you interested in Typescript, GraphQL, or React.js you might like my channel https://www.youtube.com/c/benawad97


short term vim slows you down, long term vim speeds you up


1. Create a login mutation which creates a session and sends back a cookie.

2. Use resolver middleware to check whether the user is authenticated.

I like to use express-session (https://github.com/expressjs/session) for part 1 and graphql-middleware (https://github.com/prisma/graphql-middleware) for part 2.


"Redux is notorious for its boilerplate and has a relatively difficult learning curve. We provided generators for some common templates but it was still one of the most challenging pieces and source of confusion while working with React Native."

Interesting to see even Airbnb struggles with Redux


A big contributor to the difficult learning curve in Redux is the very poor naming of things. It's off the charts unintuitive, especially if you're an experienced programmer.

I imagine their thought process went like this:

Types: People like strongly typed languages, maybe if we call our events "types", they will like Redux more?

Reducers: Switch statements are so boring and uncool. Lets call this "reducer" instead of "events switch statement".

Store: Lets call the state tree "store". The term "State tree" is too explicit and a core principle of Redux is misdirection.

Actions: Mere mortals will associate the term "action" with functions and procedures, but Redux is not for mortals. "Action" will be our term for payload.


Given that Redux is an implementation of the Flux pattern, your grievances may actually be with the naming conventions in Flux itself.

https://facebook.github.io/flux/docs/in-depth-overview.html#...


Your Flux/Redux point is a distinction without a difference. The names are bad, wherever they came from.


This is the thing that everyone seems to have forgotten. Redux didn't invent these terms out of nothing. Redux was specifically written as an implementation of the Flux Architecture, and the terms "store", "action", and "type" came directly from Flux. The term "reducer" had been in use with Clojure already, I think, and is based on the way these functions have the same signature as a callback you pass to `Array.prototype.reduce`. "State" is a generic term meaning "data in your app", and the term "tree" for a hierarchy of objects has been around for ever. (Oh, and you can write your reducer functions with _whatever conditional logic you want_ - switch statements just happen to be an obvious way to handle multiple values for a single field.)

I covered a lot of the history and thought behind Redux's design in my post "The Tao of Redux, Part 1: Implementation and Intent" [0] .

Sure, I'd agree that the terms are a lot to take in for a new learner, but claiming these were chosen or made up to make things more confusing is ridiculous. There was a lot of debate over exactly what terms to use during the development process [1] [2] [3], and it was ultimately decided that keeping the Flux-based terminology made the most sense at the time, because most people coming to Redux were familiar with Flux already. Obviously the dev landscape has changed since then, since nobody seems to remember that the original Flux concept existed, but the terms are now set in stone because we've been using them since the beginning.

[0] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...

[1] "reducers": https://github.com/reduxjs/redux/issues/137

[2] "state", "store", "dispatch" : https://github.com/reduxjs/redux/issues/113 , https://github.com/reduxjs/redux/issues/137

[3] "actions" vs "events": https://github.com/reduxjs/redux/issues/384 , https://github.com/reduxjs/redux/issues/377 , https://github.com/reduxjs/redux/issues/891


One other addendum:

The "store" is the object returned from `createStore()`, which has the `dispatch`, `getState`, and `subscribe` methods.

The store object contains your "state" value, which could be a simple number by itself, an array, an object, or whatever else you return.

Typically that top level value _is_ an object with other values nested inside of it, and _that_ is your "state tree". So, the "store" contains the "state tree", and they are not the same thing.


The cognitive overhead of redux ends up being pretty high due to the boilerplate in my opinion. It feels like complexity increases very linearly as project size goes. I've found that MobX translates to a much simpler mental model, though it does have a variety of quirks to deal with that Redux doesn't face (like converting objects to non-observable for test case assertions)


Yeah, MobX is significantly easier to reason about, even if it may have a few idiosyncrasies that make debugging more challenging. Also, performance optimization of React components is a cinch with MobX and a nightmare with Redux.


Can you explain what you mean by "perf optimization is a nightmare with Redux" ? Generally, Redux helps improve performance in a React app, especially as you connect more components.


Let's say you have a component deep in the hierarchy that needs to update based on a small but frequent change in a large object (thousands of keys). With Redux, you have to figure out how to diff the old and new copies of that object to figure out what changed. With MobX, you just observe the value of the exact key you're interested in.

That's just one example, but I generally spent a ton of time writing complex shouldComponentUpdate functions and therefore making lots of mistakes with Redux. I've found MobX much more suited to building complex UIs with deep hierarchies and tens to hundreds of total elements on the screen at once, where updating only exactly when necessary is critical.

I use MobX for my game Falcross, which I wrote about in the State of React Native 2018 thread from a few days ago: https://news.ycombinator.com/item?id=17316877

I initially used Redux, and I found it actually technically impossible to get the game to perform well using Redux. I tried everything.


I'd agree that MobX generally gives you good performance out of the box, but I'd definitely disagree that Redux's performance situation is a "nightmare".

One of the keys to good Redux performance is to connect more components, and have each component only extract a small piece of the state [0]. Using memoized selector functions also helps in most situations [1].

FWIW, there was a really good discussion on the relative strengths and weaknesses of Redux and MobX in regards to performance a while back [2].

[0] https://blog.isquaredsoftware.com/2017/01/practical-redux-pa...

[1] https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-us...

[2] https://www.reddit.com/r/reactjs/comments/5hf4d4/an_artifici... (see the linked article, the Reddit comments, and the links in the comments).


I really like that mobx + vuex have their version of "memoized selectors" (computed getters) straight out of the box, fully integrated. They're so insanely useful.


I strongly agree with the 'cognitive overhead' comment.

I think, a number of challenges that Redux and MobX are intended to address, can potentially be resolved in more elegant and easy manner with the new (16.3.1 and above) Context APIs. ReactNative 55.+ works with 16.3.x and 16.4.0 so these APIs are available to your react native apps now.

For example making available global stores to all the components that need them, being able to invoke 'render' on the interested components, when a particular store is being updated -- all of that is being supported. All that without passing the store as property through the hierarchy depth.

for the cases where your component relation is 'horizontal', rather than hierarchical. I recommend simply to use pubsub.js. It is a library that has 0 dependencies (rarity in JavaScript ecosystem :-) ). and has both Sync and Async publishing via channels. So that you can pause your publishing to the horizontally-connected components, if you need to, and then resume -- when the publishing is done.


As a Redux maintainer, I'd be really interested to know what approaches they used, and what sorts of difficulties they had.

(I'll throw out my obligatory comment that you are always welcome to use as much or as little abstraction as you want on top of Redux, and there's plenty of options available to trim down "boilerplate" depending on your situation.)


"Requires boilerplate" will forever be a criticism of Redux unless redux itself takes the (radical) decision to get rid of the boilerplate.

Just saying "well you don't need to use it" means that Redux maintains all that crust and cruft of boilerplate which remains a huge cognitive impact not only on beginners but also possibly experienced Redux users.

Redux is magnificent, but it should take a lesson from create-react-app which did the job of getting rid of all the crap that webpack and babel disastrously imposed on all JavaScript developers with their "maximum config" approach as opposed to zero config.

The message to JavaScript library and tools developers is "get rid of your config or some other tool will come along and do it for you". Redux's boilerplate is just config. If you apply every brain cell you have to the task of getting rid of boilerplate, what would Redux be left with? That's what it should be.

I think the success of VueJS can be laid squarely at the feet of the complexity of the ReactJS ecosystem - not even necessarily React itself. Every part of the larger React ecosystem needs to reduce the cognitive load it imposes and the primary task there is getting rid of configuration/boilerplate.

My theory is that "all software that CAN BE more simple is replaced by some other good enough solution that IS more simple". Thus VueJS, which whilst I wouldn't use it, is certainly simpler for beginners to grasp.


Part of the issue is that _everyone_ has a different definition of what "boilerplate" means.

So, legit question: what do _you_ mean by that term? Use of actions? Action creators? `connect()`? Immutable update logic in a reducer? Store setup?

I honestly get frustrated that people keep throwing around that term, but few people seem to point to a specific _thing_ that can be improved. (People also don't seem to understand the context that Redux came from and the intent behind its original design, something that I tried to capture in an extended blog post a while back [0]).

Early last year, I filed an issue asking for discussion of ways we can improve the learning / getting started experience, and resolve some of these "boilerplate" complaints [1]. There were a bunch of comments and some decent ideas, but I already have a lot on my plate, and no one from the community really stepped up to help push any of the ideas forward.

I do have a small "redux-starter-kit" lib [2] prototype that I've put together as a tool that can help simplify the store setup process and reducer logic. Again, though, I haven't had time to do much more with it myself since I first threw it together.

I am _always_ open to legit suggestions on ways we can improve the docs or find ways to make using Redux easier. Unfortunately, it seems like very few people are interested in actually getting in touch with us and offering assistance in doing so.

[0] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...

[1] https://github.com/reactjs/redux/issues/2295

[2] https://github.com/markerikson/redux-starter-kit


For me it is specifically this.

Here is a class:

  import React from 'react'
  
  export default class class ChooseFontLevel1 extends React.Component {
  
    constructor(props) {
      super(props)
    }
  
    render = () => <span>foo</span>
  }
And here is the (almost) same class, with the boilerplate required to use Redux:

  import React from 'react'
  import {connect} from 'react-redux'
  
  class ChooseFontLevel1 extends React.Component {
  
    constructor(props) {
      super(props)
    }
  
    render = () => <span>foo</span>
  }
  
  
  function mapStateToProps(store, ownProps) {
  
    return {
      fontPreviewsCache: get(store, `fontPreviewsCache`),
    }
  }
  
  function mapDispatchToProps(dispatch) {
    return {
      onTodoClick: id => {
        dispatch(toggleTodo(id))
      }
    }
  }
  
  export default connect(mapStateToProps, mapDispatchToProps)(ChooseFontLevel1)

To use Redux I need to entirely restructure my code.

And if the comment is "You don't need all that stuff", then why is it an option at all?

Also mapStateToProps is poorly named and confusing because it isn't talking about anything to do with ReactJS component state, although it's a reasonable assumption, it's talking about the Redux state... there's a bag of confusion for you and enough to make a beginners head spin because their head was already spinning about what ReactJS state is.

I'd also suggest that Redux has made a rod for its own back by calling "the thing that gets data out" as "reducers", instead of something like "getters". "Reducers".... argh we're now in computer science land and not the land of the practical programmer. A reducer, what is that? Beginners certainly don't know and you have to learn and become experienced with Redux to come to understand that in fact a Reducer is

Equally, cognitive load would have been reduced if actions were named "setters" or something familiar and similar to the actual functionality.

Redux itself isn't that hard once you understand it, but it's put up big cognitive barriers around itself so that you need to be an expert to eventually discover that you don;t need to be an expert.


Well, the `mapDispatch` example can certainly be simplified. `connect` supports an "object shorthand" - just pass an object full of action creators as the second argument, and they'll all be bound up and passed in as props. So, your `mapDispatch` example can just be:

    const actions = {onTodoClick : toggleTodo};

    export default connect(mapState, actions)(ChooseFontLevel1);

Other than that... there's 1 import line for `connect`, 1 function call to `connect`, and the `mapState` function.

Is that truly too much to write? Also, how does that qualify as "entirely restructuring your code"? Your component is still the same - it's getting data as props. It's just now getting them from a component that was generated by `connect`.

The alternative is to write the store subscription code yourself, by hand, in every component that needs to access the store. I've got some slides at https://blog.isquaredsoftware.com/presentations/workshops/re... that show what that would look like, and THAT would truly become tedious and painful.

The point of `connect` is to abstract out the process of subscribing to the store, extracting the data your component needs, and only re-rendering your real component when that data changes.

As for the naming of `mapState`: the word "state", in general, means "data that represents what's going on in my application". So, there's the generic aspect of "state", there's "state that is being stored in my React component", and there's "state that is being kept inside my Redux store". Those are all valid uses of the word "state" (and especially given that the Redux core is entirely independent of React).

The term "action" comes from its original design as an implementation of the Flux architecture (which is part of my point of people not being familiar with where it came from). "Reducers" comes from the `someArray.reduce()` method.

(Also, note that in both of your examples, the constructor isn't actually needed because you're not doing anything meaningful in there, and your `mapState` example isn't making use of the `ownProps` argument and therefore shouldn't declare it for performance reasons.)


Easy for you (and me to some extent) to read what you say and see hey yes it could be more simple....

What is simple for any Redux-experienced person is a gigantic cognitive cliff for people who are not experts. I can still remember trying to learn ReactJS and Redux and bailing out on Redux while I tried to make sense of mapping dispatch to props. Redux should not be losing users at that point.

Your earlier post expressed frustration at not being able to get people to be specific about what boilerplate is.... well this is it (or my definition anyway).

IMO, ideally Redux would be nothing more than an object that I instantiate and then call methods and properties on - including defining my reducers and actions. A single object for Redux leaves the question of how to ensure that changes to the Redux store result in a props refresh being pushed down through the component hierarchy, but surely the big brains on the ReactJS project can come up with some other way to handle that behind the scenes rather than me needing to change my code structure.

And may I say I love your work and I'm a big fan of Redux!

Although if I found something that operated like I say - a single object to be instantiated and driven via methods and properties with total immutability, with changes resulting in a props refresh on update, then I'd switch.


Unfortunately, the library you describe wouldn't be Redux at all. Part of the core point of Redux is to separate out the act of describing some event or update that needs to occur, from the process of applying that update. That's what makes time-travel debugging possible, and it allows middleware to modify the actions that are passing through the store. In all honesty, if you want objects with methods, MobX is what you're looking for.

Not quite sure what that "single object" sentence is trying to say, but that also sorta sounds like MobX's wrapping up of components with `observe()` (which ultimately does the same kind of thing `connect` is doing, just in a rather different way).

(Also, fwiw, Redux is completely separate from the React team. Dan Abramov and Andrew Clark, the creators of Redux, _do_ work on React at Facebook now, but Redux is not a Facebook project, and Dan and Andrew are no longer active maintainers. We talk with them a lot, and they obviously have a vested interest in Redux, but it's separate.)

And thanks, appreciate the compliment.


> Redux is magnificent, but it should take a lesson from create-react-app

...which is ironic, considering the fact that Dan Abramov (co-)created them both.


Those libs add some "magic" which is going against the point of Redux (knowing exactly what's going on). Instead of those abstraction libs I like to use the observable pattern with Rx or MobX


Depends on what your definition of "magic" is.

For example, we specifically have a "Reducing Boilerplate" docs page [0] that talks about writing reusable logic for reducers and action creators, like "higher order reducers" or a `createReducer()` util that accepts a lookup table of action types to handler functions. There's many existing libs that implement this kind of pattern [1].

Beyond that, there's other libraries that provide a higher level of abstraction, like automatically generating logic to handle common use cases (normalizing data, updating certain fields, etc) [2].

Updating data immutably can become complex [3], so there's a lot of immutable update utility libraries out there [4]. I recommend Immer [5], which lets you write normal mutative code but then applies the updates immutably.

Finally, there's frameworks built on top of Redux, like Kea and Rematch [6].

So, plenty of options available, depending on what you're comfortable with.

[0] https://redux.js.org/recipes/reducing-boilerplate

[1] https://github.com/markerikson/redux-ecosystem-links/blob/ma...

[2] https://github.com/TheComfyChair/redux-scc , https://github.com/Bloomca/redux-tiles

[3] https://redux.js.org/recipes/structuring-reducers/immutable-...

[4] https://github.com/markerikson/redux-ecosystem-links/blob/ma...

[5] https://github.com/mweststrate/immer

[6] https://github.com/keajs/kea , https://github.com/rematch/rematch


It's really amazing to see Redux, and then go and use the Elm architecture.

The Elm architecture is so simple you could write the API on a business card, and it fundamentally does the same thing, and solves the same problem. There's almost no accidental complexity, only essential complexity.

Redux on the other hand feels like there's so much accidental complexity, but it's not even obvious, it's masquerading as essential complexity.


It feels like an emperor with no clothes situation. Redux is obviously terrible but the community has adopted it none the less.


> Interesting to see even Airbnb struggles with Redux

I mean even the creator of Redux says you probably don't need to use it or if you do not all of it. It's overly complex for what it is meant to do, IMO. I had issues figuring it out initially and now if I don't touch it for a few months I feel like I have to re-learn how parts of it work because I forget and it doesn't feel intuitive to me.


Having never worked with Redux, what is its point? Is it really so hard to stick app state in a JS object and databind off that?


Yes and no.

The main point of Redux is to make your state updates predictable and traceable throughout the codebase.

Sure, you can create a global object and stuff your data in there. But, if any random part of the app is allowed to modify that object at any time, then it's a lot harder to understand how your app got into a particular end situation.

Redux is based on the "Flux Architecture" concept, and asks you to follow restrictions on how you structure your logic. Only certain functions are allowed to update the state, and in order to run that logic, you create plain JS objects called "actions" that describe some event or update that needs to occur, and ask the update logic to determine the new state values in response.

This adds a level of indirection to your code, but it provides a way to log and trace when, where, why, and how a given piece of state got updated.

If you've got about 45 minutes, I did a "Redux Fundamentals" presentation at Reactathon a few months ago that walks through the basic principles of Redux. Here's a link to the video and the slides:

https://blog.isquaredsoftware.com/2018/03/presentation-react...


In a simple app, no. In a really big app with tons of interdependent, asynchronously loaded state? Have fun.

Redux definitely has too much boilerplate, but it does an excellent job of keeping functionality decoupled, and on a big project this ends up being way more important. When you do it right, you rarely introduce regressions when working on new features, because almost everything you do is additive: you're adding new state, new actions, new selectors, new sagas, etc., without touching any pre-existing functionality or anything that pre-existing functionality depends on.

The alternative is playing an endless game of whack-a-mole as an app gets too large for anyone to keep track of what depends on what.


> The alternative is playing an endless game of whack-a-mole as an app gets too large

An alternative is another state management library.


Yeah sorry, I didn't mean to imply that redux is the only option. I meant that whack-a-mole is the alternative to using some sort of robust state management approach.


I make programming videos too, and a similar thing happens to me. The first day I release a video it's demonetized, and even if I don't request a manual review the video will be remonetized a couple days later.


Interesting. Maybe YouTube needs to adjust their algorithm for that category or something.


I'd bet this behavior is their algorithm "working as intended".

Aka, advertisers saying they don't want to waste ad spend on worthless programming videos. So they get demonetized for the first few days to reduce the impact of any ad spend on the times that would be most likely to get views, then turn it on so the drip of ad spend can treat the videos like problem children.


I'm more inclined to think that the algorithms are just a bit naive at this point. Surely some advertisers out there do want to target that market.

The notice on my videos is: Limited or no ads due to content identified as not suitable for most advertisers[1]. Your video remains fully playable and is eligible to earn subscription revenue from YouTube Red.

[1] https://support.google.com/youtube/answer/6162278?hl=en


Sure, just curious that the videos would be monetized after the first few days. From what I've heard the first few days of a video basically makes/breaks a lot of videos as far as monetization goes.


My guess is at this early stage of deployment, videos flagged by the algorithm to be demonetized (or a sample thereof) are automatically put into some manual review queue, for training and validation, which takes a few days to process through the volume.


Keep your eye on their 10Q statements next quarter. If it is what you say, it should turn up in the financials.


Udemy does a lot of advertising.


If I had to guess, videos consisting of mostly text (screencasts/slide shows) are considered likely to be bad videos (spammy junk and make-money-fast scams) and programming stuff is getting caught in the crossfire


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: