Pre-talk talk
what you will know three years from now.
The Path To Web Development
Build your callus without becoming callous
Impostor syndrome will go away
The only one you need to be better than is your past self.
Stack Overflow 2018 Developer Survey
Just because impostor syndrome goes away doesn't mean that you no longer feel out of your depth. It's just the depths you feel out of are deeper.
Fail Early. Fail often
Fail to learn a new language. (You might learn something else in the process)
Fail to use a new framework. You may hate it, but at least you'll know WHY you hate it.
Flub a job interview.
Wipe out a database. But hopefully not in production - there's such a thing as failing TOO much...
Real World Problems
& the early stages of startup life
Brian Boyko
Sr. Front-End Engineer @ Deverus
CTO, Freety.me
Hack Reactor Grad, Oct. 2015
brian.boyko@gmail.com
Our startup: Freety.me
Started as Adam's idea: How can board gamers organize their game nights? (Had the idea since 2008, but didn't have the coding background.)
My realization: Specific case of general problem.
- Is there demand in the market? Yes
- Is it feasible to build the product? Yes
- Is it possible to turn the demand into cash flow? Yes
- Can it scale?
Our product idea: a "Social Scheduler"
Other Solutions: NO. Our solution: YES.
Where we are now:
We've signed the papers which give Adam 50.01% ownership and me 49.99% ownership of the company.
We have no outside funding - we've both pledged that we'd be willing to spend $10k out of our pocket (mostly for small costs like hosting fees, services...) We've spent about $200 of it.
We've built out a back-end and API to handle the hard work of managing the data.
Currently we're building out the front-end prototype using React.
Important: Both Adam and I are keeping our day jobs.
Where we are going:
We're desperately hoping that Facebook or Google don't figure out what we've found out, because they could throw 30 engineers at us and beat us to market - so we have to keep the details hush-hush until we're ready to launch.
Our self-imposed deadline for full launch: SXSW 2019.
We're assuming at this point that we'll go for the freemium model
We'll know this has true viability as a business when we reach 100,000 users with a semi-steady revenue stream.
HBO's Silicon Valley vs. Reality.
Fiction: Venture capitalists will throw money at your idea
Fact: You need a product. Ideally, a product with both an existing user base and a revenue stream.
Fiction: Hire your friends.
Fact: Do most of the work yourself, hire cheap Ukranian contractors for QA if you have to.
Fiction: Quit your job, follow your dreams.
Fact: Keep your job, take reasonable risks with known consequences, work a combined 70+ hrs/wk.
Fiction: Techies should start their own companies.
Fact: Most successful startups have at least a "business co-founder" and a "technical co-founder"
That said:
Do sideprojects. Even if you don't have a million dollar app idea, you will always learn more, and be better positioned to do that million dollar app idea.
Working on side-projects can help you greatly with helping you stand out at your day job because you will be picking up new skills and applying them to the business.
So long as you don't risk more than you're able to lose, running your own business can help you understand the needs of your day job, and even if you have to be an employee, it can make you a better one.
New topic:
When am I gonna use this stuff in the real world?
When am I ever going to use this stuff in the real world?
- Assigning values vs. passing references (pointers)
- Functional vs. Object Oriented Programming
- Data Structures
- Algorithmic Complexity
HR throws a lot of confusing stuff at you.
I don't really have a thesis for this talk.
This is just some stuff where thinking about problems using the fancy stuff at Hack Reactor that I thought was a little too esoteric to be practical paid off, big time.
- Job: Deverus Front-End
- I had been doing most of my FE dev work in React, with Redux
- Product Manager decides future development will be done with Vue.js, with Vuex.
PROBLEM: No matter what I did, I couldn't trigger the front end view to "re-render" and show the changes when the state changed in the Vue app.
Programming Paradigms.
React and especially Redux were built on "Functional Programming" paradigms. In FP:
- You try to avoid "mutations" - returning a newly created object (or array, or value) rather than changing a value inside the function.
Vue is based on Observables
- Observables trigger other functions to run when a value is mutated.
But what was happening?
My flaw:
Whenever I mutated the root "state" object, by reassigning one of it's properties, in Vuex, it would trigger the changes, as it would detect that the value had mutated
But when I mutated the properties (if they were objects) those wouldn't register as mutations of the main state object, and wouldn't trigger the observable.
let state = {
foo: {
bar: {
baz: "quux",
}
}
}
// this will trigger a render:
const mutateFoo (newValue) => {
state.foo = newValue
}
// this will not
const mutateBar (newValue) => {
state.foo.bar = newValue;
}
let state = {
foo: {
bar: {
baz: "quux",
}
}
}
// this will trigger a render:
const mutateFoo (newValue) => {
state.foo = newValue
}
// this will not
const mutateBar (newValue) => {
state.foo.bar = newValue;
}
A Point of Pointers
When you reassign state.foo in mutateFoo, the pointer that points to "foo" changes.
Since that changes, "state" has mutated.
When you reassign state.foo.bar, however, while foo has mutated (by changing the pointer to foo.bar), state.foo still has the same pointer.
To the observable, state looks like it has not mutated (because it hasn't.)
probably wouldn't have figured this out if it wasn't for studying C, which wasn't required for my job or part of HR. See! Sideprojects FTW!
SOLUTION
Use Object.assign() to create a new object (with a new pointer) on a change.
let state = {
foo: {
bar: {
baz: "quux",
}
}
}
// this will trigger a render:
const mutateFoo = (newValue) => {
state.foo = newValue
}
// this will not
/* const mutateBar (newValue) => {
state.foo.bar = newValue;
} */
const mutatebar = (newValue) => {
const fooCopy = Object.assign({}, state.foo);
fooCopy.bar = newValue;
state.foo = fooCopy
}
Data Structures and Algorithmic Complexity
I've been building Freety.me for a year now.
I had to throw out my first eight months worth of work completely.
The problem
Create a scheduling site that automatically created meetings for you based on location, open schedules, and mutual interests.
Then we tried to build it.
(each user) x (every other user) x (all the possible times) x (all the possible interests) x (each location) x (each other location) =
... a gabazillion calculations
Adam and I couldn't figure out why no one had done it.
From Tables To Graphs
What we needed to do was change the way we thought about the problem. We figured we'd just store everything in SQL and use existing tools like join tables to speed things up.
But I remembered that there was a data structure sprint here at Hack Reactor... and remembered the graph.
Looking for matches among billions of users is a "needle in a haystack approach"
Graph
In a graph, you store pointers to other nodes in the graph.
So, if we started each query from a node, we would ONLY have to consider (through recursive traversal) positive pathways. (I.e, if the path didn't match, we just wouldn't search the node - or any of the other nodes they led to.)
We're still starting with billions of possibilities, but with each new constraint, we're eliminating the vast majority of responses, like a big binary search
Using a graph database
That brought us to using Neo4j, a "graph database" which store the data in exactly this type of graph structure.
the bad news was that I had to learn an entirely new language to use it: Cypher.
que sera
Post-talk talk
really stupid timesavers
When working with any front-end technology with mutable state (Vue, Angular, React, use
to see what the hell you're doing during the programming or debugging phass.
<pre>{JSON.stringify(state, null, 2}</pre>
Better yet, create a function to turn it on or off at the console by assigning a property to the window object.
window.toggleDebug = () => store.dispatch({ type: "TOGGLE_DEBUG" });
// reducer
export const showDebug = (state = false, action = {}) => {
switch (action.type) {
case "TOGGLE_DEBUG":
console.log(`Debug Mode ${!state ? "ON" : "OFF"}`);
return !state;
default:
return state;
}
};
// components/ShowDebugInfo.js
import React from "react";
export default props =>
props.showDebug ? <pre>{JSON.stringify(props, null, 2)}</pre> : null;
Never commit your passwords or API keys. Create a file called "secret.env" that can be different on your dev, stage, and production environments.
PORT=4000
GMAIL_USER="no-reply@freety.me"
GMAIL_PASSWORD="dontshowapasswordinaslidedeckeither"
MONGO_URL="mongodb://localhost:27017"
MONGO_DB="freetyme"
NODE_ENV="development"
SENDGRID_API_KEY="iaso;hdfopahsip;haiopdhnivaopnwsiopvnaiopsnruvipausdpbn[v"
API_URL="http://localhost:4000"
TWILIO_API_KEY="asdfhopaisopnviaopswnidopavi"
TWILIO_ACCOUNT_SID="asdfioaphsjidfnpaisdf"
TWILIO_PHONE_NUMBER="+1343434343"
TWILIO_VERIFY_URL="https://api.authy.com"
SECRET="I have a crush on Tilda Swinton"
DARK_SECRET="I enjoy My Little Pony Non-Ironically"
You can then use the "dotenv" NPM library to include them in your project.
import path from "path";
require("dotenv").config({
path: path.resolve(__dirname, "..", "..", "../secret.env")
});
export const config = {
secret: process.env.SECRET,
darkSecret: process.env.DARK_SECRET,
neo: {
login: process.env.NEO_LOGIN,
password: process.env.NEO_PASSWORD,
},
port: process.env.PORT || 8080,
gmail: {
password: process.env.GMAIL_PASSWORD,,
user: process.env.GMAIL_USER,
},
sendgrid: process.env.SENDGRID_API_KEY,
twilio: {
apiKey: process.env.TWILIO_API_KEY,
apiUrl: process.env.TWILIO_VERIFY_URL,
}
};
export default config;
If your webpack.config file becomes too unwieldy, remember that Node 8.10LTS or better has support for require() and module.exports out of the box.
const path = require("path");
const entry = require("./webpack/entry");
const output = require("./webpack/output");
const plugins = require("./webpack/plugins");
const resolve = require("./webpack/resolve");
const rules = require("./webpack/rules");
const devServer = require("./webpack/devServer");
const config = {
entry,
output,
plugins,
resolve,
devServer,
module: {rules},
context: __dirname
};
module.exports = config;
Javascript does not have a built-in "enum" type, like C# or other similar languages. But it's five lines of code to hack one.
const makeEnum = (...strings) =>
strings.reduce((pv, cv) => {
pv[cv] = cv;
return pv;
}, {});
export default makeEnum;
const status = makeEnum(
"ATTEMPTING_LOGIN",
"AUTHORIZED",
"UNAUTHORIZED",
);
export const signIn = ({ login, password }) => dispatch =>
new Promise((resolve, reject) => {
dispatch(setAuthStatus(status.ATTEMPTING_LOGIN));
request
.post(`${URL}/authenticate`)
.send({ login, password })
.then(result =>
resolve(dispatch(setAuthStatus(status.AUTHORIZED))))
.catch(
.catch(forbidden =>
reject(dispatch(setAuthStatus(statTypes.UNAUTHORIZED))))
});
dispatch(setAuthStatus("UNAUTHORISED"))
// does not throw an error
dispatch(setAuthStatus(statTypes.UNAUTHORISED))
// throws an error.
Q&A
the post-post-talk
Third talk
By brianboyko
Third talk
- 710