• About
  • Development
  • Music
  • Photography

Thomas Shellberg

  • Anti-anti-fragility

    January 12th, 2023

    The downturn of the global economy and in particular the latent fear within the tech industry has made the term “Anti-fragility” show up more and more frequently. It seemed to have been coined by Nassim Nicholas Taleb in his book Antifragile: Things That Gain from Disorder.

    A commonly cited scenario when discussing anti-fragility is handling a wine glass. The wine glass is fragile because it is brittle and has a “non-linear response to shock”. This means that up to a certain level of shock the glass remains intact but it will suddenly break at a certain stress level, spilling its red liquid contents all over the white carpet.

    I think there’s more nuance to this scenario, though, and what follows is my attempt to better define fragility.

    Compare a wine glass to a blob of Play-Doh; we wouldn’t consider Play-Doh to be fragile. We consider a wine glass to be fragile because it’s easily broken into multiple pieces, however, you could rip a blob of Play-Doh in half. Isn’t that broken as well? For some reason, we don’t consider that to be broken, because you can reassemble it. Whereas a wine glass seems impossible to re-assemble, you can put the pieces of Play-Doh back together into one cohesive piece.

    Can you really, though?

    Mental Models

    What we would say makes the wine glass fragile is that if it breaks it’s not easy to put back together. Why is it hard to put a wine glass back together but not a ball of Play-Doh? The problem is that we have a rigid concept of what constitutes a wine glass. We have a distinct visualization of the form of the wine glass and even if you were to glue the pieces back together it may not be as functional as it was before. Or, its new structure may entirely break the mental mental model we have of a wine glass!

    Contrast that with our mental model of a blob of Play-Doh. This model is pretty loose; it’s just an amorphous, non-specific ball. If you were to rip it apart and put it back together, from an exact atomic definition it’s not the same ball as before, however, according to your mental model, it’s pretty much the same thing. The usefulness has not changed. Or, perhaps the Play-Doh has such low usefulness that it’s hard to make it worse.


    Our mental model of a wine glass comprises quite often a specific shape, texture, and, most importantly, that it can hold wine without spilling it all over the place! If it’s so broken that filling it up results in losing all of your wine because it leaks out then you no longer have a wine glass, do you?

    The Play-Doh ball, however, is very amorphous; you can shape it however you want and in your mind it’s still the same ball of Play-Doh (but it’s not).
    The reason it’s not the same ball is related to entropy.

    Entropy Enters

    We can think of entropy in this example as the measure of disorder in a system or within an object. The Play-Doh object in our model is pretty disordered; in our minds, it doesn’t need to take on a specific shape. The arrangement of the atoms doesn’t really need to be precise for you to see a ball of Play-Doh. By contrast, a wine glass has a pretty specific combination of atoms which determine how much it looks and functions like our mental model of a wine glass.

    Thus, we have a very rigid idea of what makes up a wine glass.

    I personally like to conceptualize the entropy of the wine glass using combinatorics by asking myself, how many combinations of the random arrangements of glass molecules still make up a wine glass? And how many combinations would just look like a broken wine glass or worse, just glass particles laying on the floor?

    It seems like there are a lot more combinations of a broken wine glass with shards all over the floor. In the multiverse, there are a lot of versions of me breaking a wine glass during cleaning and cursing its fragility. It’s a miracle that they stay intact at all.

    Compare that to a ball of Play-Doh. Even without calculating combinations, intuitively it seems like there’s so many more combinations of randomly assembled Play-Doh bits that still looks like Play-Doh.

    So this (in my opinion) is really what makes a Play-Doh ball anti-fragile compared to a wine glass. There are far more combinations in which we accept this mental model versus the wine glass. There are (comparatively) not as many combinations of the arrangement of atoms that you would still say makes up a wine glass.

    Thus, it’s much more fragile.

    Relation to Organizations

    Organizations are now hopping onto the trend of labeling themselves as “anti-fragile” but it’s hard to understand what that actually means. We talk about growing through adversity but how do we actually do that? Is it just talk/mindset or is there something we can actually change at the organizational level?

    Side-note: Does downsizing an organization, losing a bunch of talent, and going into survival mode sound anything like “anti-fragile”? It’s hard to imagine the result of that is a stronger organization.

    When we imagine the organizations we interface with, do we envision them as rigid structures like a wine glass or do we view them as amorphous blobs of Play-Doh? If we have strict goals, processes, and structures within our organizations, how do we become an amorphous blob that can respond to changes in an anti-fragile way? Imagine an organization built like a fragile wine glass that is useless as soon as it’s had some external force applied to it.

    Does a company require a visible, brilliant, charismatic CEO in order to be recognizable? If they left their position, would the company lose all sense of direction and innovation? Would their share price fall?

    Tech companies in particular are slashing expenses in preparation for a perceived recession coming, including laying off thousands and thousands of tech workers. In order to reduce risk, perhaps we also need to consider what combinations of the “atoms” of people that we have in our organizations still make it recognizable.

    How could our organizations be structured so that it’s amorphous to change and not super fragile?

    Some ideas come to mind:

    • Plan for a steady, not-too-risky business growth rather than fall prey to a boom/bust cycle when an inevitable Black Swan event occurs. The idea is to outlast your competition and incrementally improve rather than bet everything on the Next Great Thing. Being “first to market” is overrated anyways.
    • Invest in people and their skills rather than rigid job titles. Smart, curious people can be moved around between projects and even take on totally new responsibilities. If a department or project needs to be put on hold or have resources diverted away from it, relocate your people to higher-potential projects/departments if you can rather than lay them off.
    • Don’t have a rigid product offering which is at risk of becoming obsolete (“we’re a smartphone company”); build things that align with your core values and solve problems rather than just make products (“we want to connect the world”).

    To actually be anti-fragile, we have to think about how to build more combinations of the “atoms” and the lattice work of our companies that are acceptable for the mental model of our successful company.

  • Math Might Help Explain Why You Feel So Imperfect

    September 21st, 2022

    You want to become a better person.

    You dig deep and come up with a list of new habits that you need to form in order to get closer to the Ideal You:

    • Get up at 5 am every day.
    • Take a brisk walk for 30 minutes.
    • Perform a 15 minute stretch routine.
    • Meditate for 10 minutes.
    • Write in your Journal.

    You’re motivated and willing to put in the work but every once in a while you’re going to not show up; that’s just part of being human.

    Let’s say for each of these individual tasks you have a 90% success rate. That sounds pretty good, right? Let’s think about our overall goal, though, because we implanted an idea in our head that our Ideal You did all of these things every day.

    What is the probability of accomplishing all of these tasks on a given day? Hint: it’s not 90%.

    In combinatorics, when we are testing the probability of multiple events happening in a specific combination, we multiply the probabilities of each individual event. So, what is the probability we will actually accomplish all of these things on a given day?

    (Get up early – 0.9) x (Walk – 0.9) x. (Stretch – 0.9) x (Meditate – 0.9) x ( Write – 0. 9 ) = 59%

    That means, although you are very good at accomplishing each individual task on a given day, the chances of you doing all of them are drastically lower than the individual percentage of 90%.

    It’s nearly a coin flip.

    What if you weren’t as disciplined and your task success rate was 80%? That shouldn’t make a huge different, right?

    Get up early – 0.8) x (Walk – 0.8) x. (Stretch – 0.8) x (Meditate – 0.8) x ( Write – 0. 8 ) = 33%!

    Even a slight difference(-10%) in our discipline at each individual task has nearly halved our success rate of an Ideal You.

    Is it easier to see now how hard it can be to become the Ideal You?

    In an upcoming post, I’ll attempt to tie anti-fragility, combinatorics, and redefining the Ideal You together such that we can perhaps have a less rigid view of our ideal selves and thus be happier (that’s always the goal, right?)

  • Mitigating Evil

    March 20th, 2020

    This is a continuation of a post entitled, Evil as an Emergent Property.

    I’m glad Google removed “don’t be evil” from its mantra.

    I can only guess as to why it was removed but it was perhaps an admission that they don’t believe in the concept of evil as we tend to define it:

    A manifestation of profound immorality and wickedness, especially in people’s actions.

    That seems like a pretty low bar to set for behavior.
    And who the hell would admit to the above anyway?

    No one, which is why it’s more important to look at systemic reasons for evil things happening rather than try to root out evil people.

    I’ve assembled some ideas around what could help stifle the emergence of “evil” within an organization. Some require careful analysis, others careful planning, and another requires old-fashioned bravery.

    Game Theory

    Applying Game Theory principles can be as simple as assuming that every individual in an organization is working to serve their best interest.

    Review the incentives in play within your organization. Are employees incentivized to turn a blind eye to corruption(do they receive bonuses)?

    Is there a culture in place that discourages people from challenging their superiors?

    You can be as morally righteous as you want—in a vacuum—but throw in a second entity and you gotta start acting in response to the other.

    Angry Zodd, Danny the Last Earth Man

    Flat Structure

    Structure your organization to have as flat of a hierarchy as possible – not just in a strict organizational manner but by maintaining a culture that allows people to interact with corners of their organization outside of their own silly little responsibilities.

    Each individual possesses a conscience which to a greater or lesser degree serves to restrain the unimpeded flow of impulses destructive to others. But when he merges his person into an organizational structure, a new creature replaces autonomous man, unhindered by the limitations of individual morality, freed of humane inhibition, mindful only of the sanctions of authority.

    Stanley Milgram

    Holistic Planning

    Having a flat structure isn’t enough to stop evil; when planning projects, you need to make sure to involve as many departments as possible such that the project has maximum visibility and transparency. This ensures that evil deeds don’t go unnoticed.

    Innovation is the lifeblood of an organization. Knowing how to lead and work with creative people requires knowledge and action that often goes against the typical organizational structure. Protect unusual people from bureaucracy and legalism typical of organizations.

    Max De Pree

    Civil Disobedience

    Don’t just follow orders. You won’t be protected by your employer anyway.

    Build a valuable skillset that allows you to live without fear of being unable to feed yourself and your family.

    Live minimally so as to not become beholden to a decadent lifestyle and save enough to be able to quit if your conscience demands it.

    …but if it is of such a nature that it requires you to be the agent of injustice to another, then I say, break the law. Let your life be a counter-friction to stop the machine. What I have to do is to see, at any rate, that I do not lend myself to the wrong which I condemn.

    Henry David Thoreau, Civil Disobedience and Other Essays

    Anonymous Discussion/Feedback

    Provide ways for your employees to deliver feedback anonymously.

    One potential model involves 360 degree feedback. So named because of its all-encompassing reach, 360 Degree Feedback is an information gathering method that allows employees of all ranks and titles to receive confidential and anonymous feedback from coworkers. The model is simple enough: workers complete a feedback form that spans several different office competencies in regards to other employees and departments.

    Study.com

    Provide an anonymous forum for your organization where sensitive topics can be explored without fear of repercussions or revenge. Ensure that the forum users can self-moderate and that topics are relevant to your organization; don’t let your company forum devolve into 4chan.

    Conclusion

    I stated in the last post that I don’t believe that people are evil. Rather, people will adjust to become what the system allows them to be. They will be as good or as bad as the structure and incentives nudge them to be.

    Our current low-attention culture fixates on individuals and applies maximum wrath to destroy those they think are responsible for “evil”.

    But perhaps “evil” deeds arise through mismanagement, disorganization and apathy rather than pure individual wickedness.

    The evil that is in the world almost always comes of ignorance and good intentions may do as much harm as malevolence if they lack understanding.

    ALBERT CAMUS, The Plague
  • Evil as an Emergent Property

    March 2nd, 2020

    If only there were evil people somewhere insidiously committing evil deeds, and it were necessary only to separate them from the rest of us and destroy them. But the line dividing good and evil cuts through the heart of every human being.

    Alexander Solzhenitsyn, The Gulag Archipelago

    Solzhenitsyn believed that all people were capable of taking part in evil actions and that it was pointless to spend our time searching out people we considered to be pure “evil”.

    And yet, horrific things happen every day in the world that seem to only be explained by the existence of “evil”. How do we reconcile this with the belief that we are all good people?

    It’s my hypothesis that evil people aren’t required for horrific acts to occur. Rather, evil is actually an emergent property, meaning that an evil machine can arise although none of the aggregate parts of the machine are evil. How is this accomplished? Two parts: compartmentalization and bureaucracy.

    Compartmentalization

    This is both a top-down and a bottom-up phenomenon.

    Top-Down compartmentalization refers to the physical separation of departments and responsibilities.

    Bottom-Up compartmentalization refers to the psychological processes individuals themselves employ, generally as a defense mechanism.

    Top-Down

    The top loves compartmentalization because it’s easier to impose their will upon the organization. This isn’t by itself evil, by the way, it’s just self-serving. If I believe my vision for the organization is what is right for the organization, I want as few barriers as possible to creating my vision. If you love Elon Musk, you want him to be able to impose his vision on the world without much impediment. We want to support our benevolent monarchs but we risk giving a tyrant power once the monarch is gone. The danger is creating a system that has no checks against evil should it eventually present itself.

    Bottom-Up

    The bottom has incentives to love compartmentalization, namely:

    • Intellectual/physical laziness.
    • Monetary rewards for keeping their job.
    • Cognitive dissonance(refusal to see evil).

    The bottom has an incentive to ignore evil and only go about their day-to-day jobs. I’m a truck driver at Auschwitz; my family is starving back in Germany since the fall of the Weimar Republic and driving for the Army pays well. They provide everything I need so I can send my salary back to my family. I don’t want to question what’s happening inside Auschwitz because it threatens my ability to provide for my family. So I purposefully compartmentalize my job and only do what I’m told; I deliver thousands of pounds of cargo but don’t dare to look to see what’s inside of those pallets.

    Bureaucracy

    The second ingredient is a system that frustrates whistle-blowers and dissidents into giving up their quests for ridding evil. This is done through a web of bureaucracy. A particularly effective version is one that disguises itself as a guardian of security and public health. One could imagine examples of this being three-letter government departments(EPA, FDA, DoE). Simply creating a system that is intentionally difficult to navigate will eventually be sniffed out so it works best by having a system of red tape that’s purpose is to safeguard:

    • Fraud(internal and external)
    • Public health
    • Privacy
    • Trade secrets
    • Product quality(QA)

    The setup of these systems would be questioned if done only to create organizational quicksand so be sure to compartmentalize the decisions and jobs as much as possible.

    The Way Forward

    So, if the theory holds up that evil can propagate without evil people existing in a system, what do we do with that knowledge? How do we stop its propagation and organize ourselves to limit its emergence?

    We’ll explore that in the second part of this blog series. šŸ™‚

  • I’m Building an App – Just Publish it Already

    June 28th, 2019

    Recap

    My plan is to progressively enhance the app into a fully complete app, allowing me to step-by-step learn important principles of development without overwhelming myself while at the same time practice my learning by applying them to a real app.

    I did it.

    I crossed the nebulous divide that separates an amateur from a professional. I finally feel like I can truly hack it as a developer. It came at a very clear moment. How did I know this, and how did I recognize the moment?

    Because I, feeling the looming crunch of a deadline, abandoned my strict plan and decided to just publish the app.

    What Publishing to Google Play looks like.

    Jokes aside, I’m not actually abandoning my plan.

    • I will be adding some form of caching to the app. My initial testing shows that the app performs fine even if contacts are fetched new every time the app loads. Perfect? Nope.
    • I will be learning how to use a profiler and really test performance. The tests I’ve run on by installing the app APK on my phone show no performance issues; it runs quite quickly without any crashes.
    • I will be ensuring my code is better documented, both through a Readme and within the code itself.

    What’s more important than those things, though, is getting quickly to the real feedback cycle. Documenting the code doesn’t help end-users.

    So, I’ve decided to publish the app in beta form on Google Play. It already has a bug that should have been spotted earlier(the splash image doesn’t fully cover the screen on all devices) but that’s been corrected and will be in the next version(See? I am a professional).

    Put Your Code In the Wild

    I’ve also taken the plunge to put the code on GitHub.

    If you are still not convinced that I’m on the top of my game, don’t think that I didn’t have to search and remove all of the crappy console.log() statements and @todo comments.

    Contribute

    Feel free to open up a GitHub issue if the following applies:

    • You spot a bug when running/cloning/building the app.
    • You have a feature request(Duh, it needs a way to import contacts from the phone. Never thought of that one).
    • To point out inefficient functions or lifecycle method usage(React is hard, y’all).
    • You feel like nitpicking my indentation, spacing, function naming, or abhorrent use of Typescript.
    • You, a headhunter, are so impressed that you want to offer me a developer position(include salary in the description).

    Conclusion

    I’ll be circling back through the remaining steps and chipping away at the repository, refactoring and cleaning up as I get better and more knowledgeable. I am under no illusions that this is a completed or perfected project but it’s been a wild ride and a great learning experience. In fact, it sounds like a “Lessons Learned” post is needed….

  • I’m Building an App – Ripping Off the Band-Aid

    June 17th, 2019

    Well, here we finally are: deep in the middle of the inevitable existential crisis that comes with building an app. We’ve built enough of the app that we have come to a point of realizing our existing architecture is not good enough.

    Managing State

    The current method of handling state in this app is ugly. It doesn’t have any real global state; most of the state is handled by the Home Screen component and data is passed from there to the other “screens” through React Navigation props.

    The Problem

    • There is a lot of copied code within different components which ultimately do the same thing – not DRY at all.
    • Things like storing a reference to the Firebase logged-in user as well as the Realtime Database weren’t done at a high-enough level in the app, meaning that several components created their own references to the logged-in user and database.
    • No global state – this makes it easy to screw up the handling of data between different components.
    • It’s hard to maintain state and props between multiple screens and multiple tabs of React Navigation as each has their own state and props and passing props can be unpredictable and easy to get wrong.
    • The functions responsible for changing data within the app end up mutating data too often.

    The Solution

    One word: Redux.

    When I first started this project, the idea of adding Redux was already in the back of my mind. However, I was intimidated by the seemingly complex Redux library. Create a store? Write reducers? Create actions? Trigger dispatches? Ughhhhhh.

    I believe the best way to learn something is to try to isolate it as much as possible down to its most fundamental pieces and build up from there. The problem with learning React is that the tutorials I found were in the context of creating a React app. It was thus adding a complex piece to an already complex puzzle.

    You wouldn’t learn how to ice skate through playing ice hockey, would you?

    Luckily, I stumbled upon a fantastic video course created by the Redux creator himself, Dan Abramov. What made it stand out was that the beginning of the course taught the fundamentals of Redux without any other libraries. Creating a working example of a Redux store all in plain JavaScript was what got me confident enough to know I could add it to my own app.

    I created a small little JSFiddle to demonstrate the basics of creating a store, reducer, action, and dispatching that action. You can check it out here.

    Back to the App

    So, how exactly am I going to use Redux?

    But First, a Principle

    Redux is a very enlightened library and as such is guided by three core principles, the first of which is:

    The state of your whole application is stored in an object tree within a single store.

    aka a “single source of truth”

    An object tree really just means that all of your global data is stored in one big object. The main state of your app should be centralized in a single location and not scattered around between various components.

    The Store

    I’ll create a single store for the app and wrap the root-level component within the store component. This gives everything in my app the ability to interact with the store(and for the store to interact with it).

    This is the setup code:

    import { Provider } from 'react-redux'
    import { createStore } from 'redux'
    import contactsReducer from './reducers/contactsReducer'
    
    const store = createStore(contactsReducer)

    This is what my main App.tsx class returns(what gets rendered):

          return (
            <Provider store={store}>
              <AppNavigator />
            </Provider>
          )

    The <AppNavigator /> component is the root component of the app; it houses all of the React Navigation components the app uses.

    That’s it for the root-level App.tsx component.

    The Actions

    Actions can best be described as the things that tell the app what happened. They are not responsible for determining what should change in response to what happens in the app. That’s the job of Reducers.

    Specifically, Actions are plain JavaScript objects which deliver information from your application to your Redux store. They can also deliver a payload of data to your store and allow your reducer functions to handle that data to calculate a new state.

    The Second Principle

    The only way to change the state is to emit an action, an object describing what happened.

    Actions abide by this principle by being the sole way we trigger app-level state changes. We never mutate state directly.

    We will first create our Actions in a file that can be imported throughout the app and specify the types of actions our app will need to perform.

    This is as simple as it gets to define an action:

    export const getCachedContacts = () => ({ 
        type: 'GET_CACHED_CONTACTS' 
    })

    What’s going to happen here(there is obviously a bit more setup to do but I’ll spare the gory details) is our Reducer function is going to look for an action with the type GET_CACHED_CONTACTS and then act accordingly. Sometimes we’ll even send a payload of data. Imagine that we don’t just want to get something but we want to send something:

    export const addNewContact = ( contact, userId ) => ({
        type: 'ADD_NEW_CONTACT',
        payload: { contact, userId }
    })

    Here, we are taking in a contact object(think, all of the details of a specific person) along with our Firebase userId(for authorization purposes) and putting them together into a single payload object.

    This action would be called as a normal function within a component using the connect() function and a custom mapDispatchToProps() function.

    Let’s see how the reducer handles these actions.

    The Reducer

    This line earlier from App.tsx is probably confusing so let’s explain what’s happening:

    import contactsReducer from './reducers/contactsReducer'

    This file is our single reducer for our app. The job of a reducer is to specify how state should react based on things that happen in the app. A Reducer doesn’t care about how it’s called. It responds to Actions, does something to calculate a new state(important: it doesn’t mutate anything) and then returns the new state. The Store then passes down that new state to the components in the app and makes sure stuff gets re-rendered where necessary.

    The Last Principle

    Changes are made with pure functions

    It’s important to abide by this core principle when creating reducer functions. You do not ever mutate state; you calculate a new state and return it.

    Example

    This is a portion of the reducer I’m creating for the app(so ignore missing brackets and parentheses).

    const contactsReducer = ( state=INITIAL_STATE, action ) => {
        switch(action.type) {
            case 'UPDATE_CONTACTS':
            if ( !state || !state.contacts && !action.payload ) return INITIAL_STATE
            if ( !action.payload ) return state
            return Object.assign( {}, state, {
                contacts: action.payload.contacts
            } )

    I have some conditional statements to make sure I’m covered in case something goes wrong in the app and the payload is falsy or state is somehow falsy.

    The clever part is through the Object.assign() method. What we’re doing here is creating a new object, passing in the existing state object, and then another object with a contacts property. If the state object already has a contacts property it will be overwritten.

    In this way, you don’t modify the state object directly; you pass in a new object and overwrite existing properties with new information.

    Test-Driven Development

    Redux reducers need to utilize pure functions. Guess what makes it much easier to write pure functions? Test-Driven Development.

    Write a test for what you expect to happen for each of your cases in the reducer function and then write the actual pure functions. You’ll uncover bugs before they happen and you’ll understand your code so much better than if you just plugged away without tests.

    Conclusion

    There’s obviously a bit more involved with adding Redux to cover the entire app but hopefully this sheds some light on the decision behind using Redux as well as the fundamental ideas behind how it actually functions.

  • I’m Building An App – Step 5 – Typescript

    June 11th, 2019

    This is the seventh post in a series of posts which will illuminate my journey to becoming a Full-Stack JavaScript Developer. Read the first one here.

    Recap

    My plan is to progressively enhance the app into a fully complete app, allowing me to step-by-step learn important principles of development without overwhelming myself while at the same time practice my learning by applying them to a real app.

    JavaScript the Dynamic Language

    JavaScript is considered to be a weakly-typed, dynamic language. A dynamic language refers to the way variables and functions are initialized while a weakly-typed language has “looser typing rules and may produce unpredictable results or may perform implicit type conversion at runtime”.

    When you declare a variable in JavaScript, you don’t need to state the variable type, it’s implicitly determined by the programming language. What’s more, the variable type can change based on reassignment.

    An Example

    Let’s say I have built a shopping cart app in JS and the app has a variable named price to record the cost of a single product. I need to not only be able to record and display this price but perform math operations with it(sum up the prices to make a Shopping Cart total, for instance).

    When I first initialize the price variable I set it to a floating point number value of 9.99. I did not specify that it was a floating point number; JavaScript figured that out for me.

    Later on, I need to display this price on the front-end and I hastily enter the price as a string of text. The JavaScript engine says, Cool, I guess this is a string now.

    Why would I do this? Perhaps I need to prepend the currency symbol($) to the price and I can’t do that with a number.

    var price = 9.99
    console.log(typeof(price))  // number
    price = "$9.99"
    console.log(typeof(price))  // string

    The Problem

    Now if I try to perform math operations on the price it’s going to fail as it’s now a string.

    This super simple example should hopefully illustrate one of the pitfalls of a dynamic language and this type of implicit type conversion is one of the biggest causes of bugs in dynamic language applications.

    Sure, it’s easy enough to notice the bug in our example but imagine the application has dozens of files and thousands of lines of code. Keeping track of all of the variables and their types in your head becomes impossible so it would be nice to have a tool that helped avoid the aforementioned pitfall.

    A Possible Solution

    Typescript is a superset of the JavaScript language which offers things like static checking and code refactoring when developing JavaScript applications. When you write Typescript it is later compiled into clean JavaScript code.

    Basically, it makes your JavaScript look like more like a strongly-typed and static language resembling something more like Java or C#.

    New Projects

    There isn’t a single initialization command for adding Typescript to your React Native app, however, specific instructions can be found here. I won’t bother going through them in this post. I can say that it was relatively easy and took just a few minutes.

    The Plan

    The nice thing about Typescript is that we don’t have to convert the entire project immediately to Typescript in order for our app to run. We can convert one file at a time into Typescript and slowly clean up our app in a measured fashion.

    What’s more, Typescript files can be just plain JavaScript, meaning that we could simply rename our .JS(or .JSX) files into .TS(or .TSX) and they would compile fine without actually adding any Typescript.

    With that in mind, we can convert our app piece by piece(or atleast, the major components) to Typescript at our own pace. We’ll start with the main entry path to the app, App.js.

    App.js

    The first thing to do is to rename the file to App.tsx. Technically, Typescript uses .ts as the file extension but we’re using some type hinting here to indicate that we’re not writing pure JS but JSX. It’s the same reason that we would previously have our file named App.jsx.

    Interfaces

    If you do nothing else other than apply interfaces to your React components you would still be improving your React code quite a bit.

    An interface is like a predefined shape for a structure which says, this is how this thing should look. We determine beforehand the logical shape of this structure so that it is stable. If we fail to build our structure to match the shape of the interface we will get an error. If we try to change the shape of the structure later we will get an error.

    The two things you absolutely need to apply interfaces to are a component’s state and props. Here’s a super easy example from the main App.tsx file:

    interface State {
      isLoadingComplete: boolean
    }
    
    interface Props {}
    
    export default class App extends React.Component<Props, State> {
      state = {
        isLoadingComplete: false,
      }
    }

    My main App file has just a single piece of state which tracks whether or not loading is complete. If it’s not finished loading a loading spinner component is rendered; if it’s finished loading the rest of the app is rendered.

    It doesn’t have any props.

    What we’ve done in the example above is set the shape of our props and state for our App component. The following will cause an error in our IDE if we fail to maintain that shape:

    • If we pass any props to this component(because none are declared in the interface).
    • If we declare any new props on the state object other than isLoadingComplete.
    • If we change isLoadingComplete to anything other than boolean.
    • Leaving out any piece of the interface object when passing props to the component(if the Props object was not empty).
    • If any piece of the Props interface did not match the declared variable type(again, if the Props object was not empty).

    It’s Just a Tool

    One thing to keep in mind with Typescript is that it will still compile your code into JavaScript if it catches errors. If there are no actual JavaScript errors the code will still run; TypeScript doesn’t prevent compiling your app if you leave out a prop or mutate a piece of state. It’s meant to warn you of potential issues with your code.

    Typescript is really a helper tool for development teams to write better code by providing warnings when our code is not taking the shape we initially agreed it would or when we return a different variable type from a function than we initially said we would. It helps us understand our code better and know what our variables should be and how our functions should act.

    There are too many files that need to be converted in this app to go over here but the idea is generally the same for all of the files:

    • Create interfaces for our Props and State.
    • Assign a type to our variables.
    • Specify the return type for our functions.

    Next

    In order to speed up this app as well as add some offline compatibility we’ll be adding some sort of caching to the app in the next blog post.

  • I’m Building An App – Step 4 – Unit Tests

    June 4th, 2019

    In the previous post we built a database sanitization function but how do we know it works other than testing directly in the app and looking at the database? We can actually do this with Unit Tests.

    In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use.

    https://en.wikipedia.org/wiki/Unit_testing

    The important bit about Unit Tests is that they should test functionality independent of external systems. This means that this app’s unit tests should only test the self-contained functions within it and not test any functions that interact with my database or with the Auth system(anything to do with Firebase, really).

    Testing functionality which integrates with external systems does have its purpose, however, that would fall under integration testing.

    Jest

    I’m going to be using Jest for unit testing here. Jest is an open-source testing framework created by Facebook with the help of many other contributors. It’s widely used by a number of giant tech companies to quickly and easily set up JavaScript unit tests.

    Since I will be performing unit tests while developing, I’ll want to make sure to only install it as a devDependency:

    npm install --save-dev jest

    In other words, we don’t want Jest to be a dependency in the production environment.

    A Gotcha

    It’s important to remember that you should be exporting the functions you are testing in your app as modules and then importing them into your tests. I have caught myself simply copying and pasting the functions from my production code into my tests, which is wrong. Not only is it not DRY but if I change those functions in my production code the tests will not reflect those changes.

    In my /functions/src/index.js file I have a function which strips HTML from each of the values of the properties of an object. I export it to make it available outside of this file.

    exports.stripHtmlFromObj = ( data ) => {
        for (const prop in data) {
            data[prop] = sanitizeData(data[prop])
        }
        return data
    }

    Importing this function into my test.js file is as simple as this:

    const { stripHtmlFromObj } = require('../functions/src/index.js')

    The reason we import it between a set of curly braces is because importing the file by itself imports one big object with all of the available functions and variables that were exported from that file. We are using object destructuring to only grab the stripHtmlFromObj() function.

    An Example

    We created a function that would sanitize input data before it is sent to the server. It works by stripping out HTML from raw text. The main inputs we have in our app are the inputs used when adding a new contact to the app. Sounds like a good thing to test.

    First, let’s try to describe what a test would do in plain English.

    • Import our own sanitization function so we can use it in our test.
    • Create an example data object that would represent a contact.
    • Add some HTML to the data object string values.
    • Write tests to check if the HTML is stripped when passed through our own sanitization function.
    • We expect that when we pass a string with HTML through the sanitization function that we return a string minus the HTML.

    If I pass the following for Last Name:

    "lastName": "<script>alert('you are screwed');</script>Shellberg"

    It should strip out HTML tags from the contact.

    I expect the resulting lastName property to equal “Shellberg”.

    The bold portions of that last sentence are not a random style choice; we effectively just wrote a Jest unit test expectation. šŸ™‚

    The Code

    Here’s an excerpt of the contacts.test.js file which tests functions that manipulate/read contact data:

    const { stripHtmlFromObj } = require('../functions/src/')
    
    describe( 'sanitize HTML inputs', () => {
    
        const data = {
            "id": 1,
            "firstName": "<strong>Thomas</strong>",
            "lastName": "<script>alert('you are screwed');</script>Shellberg",
            "birthday": "Sat May 25 2019 12:34:33 GMT+0200 (Central European Summer Time)",
            "phone": "(480)555-5555",
            "email": "greg@gregerson.com",
            "address": "21 Main St., Phoenix, 85224, Arizona"
        }
    
        it('should strip out HTML tags from contact', () => {
            const strippedData = stripHtmlFromObj(data)
            expect(strippedData.firstName).toEqual('Thomas')
        })
    
        it('should strip out HTML script tags from contact', () => {
            const strippedData = stripHtmlFromObj(data)
            expect(strippedData.lastName).toEqual('Shellberg')
        })
    
        it('should leave birthday string intact', () => {
            const strippedData = stripHtmlFromObj(data)
            expect(strippedData.birthday).toEqual("Sat May 25 2019 12:34:33 GMT+0200 (Central European Summer Time)")
        })
    
        it( 'should leave phone number intact', () => {
            const strippedData = stripHtmlFromObj(data)
            expect(strippedData.phone).toEqual("(480)555-5555")
        } )
    })
    

    Test Result

    All tests passed!

    Parting Thoughts

    We want to remember that unit tests should test functionality independent of external systems. This means that this app’s unit tests should only test the self-contained functions within it and not test any functions that interact with Firebase.

    When writing a unit test, a best practice is to write a test for every possible code route. Let’s say you have a function with an if{} else{} statement which diverts the function into two directions of flow. You should write a test for each of those routes.

    In this case we don’t have that sort of code diversion but we do have multiple ways that data could be entered. Since we know that we want to test HTML being sanitized from our data string, it’s easy to only write tests in which all of the data is dirty. We have to remember to also test clean(no HTML) data.

    Therefore, since our data object contains 6 properties, we should probably write at least 12 unit tests here(6 properties that are dirty, 6 that are already clean).

    I’ll be refactoring this code to actually put it into two different suites; one for “dirty” inputs and another for “clean” inputs.

    Unit testing React Native apps is not easy as the separation between pure functions and interactivity can be a gray area, however, we should do our best to unit test our pure functions with Jest and use additional testing libraries for integration testing or end-to-end testing.

    Next

    The next post of this series will be one of the easiest; we’ll be adding Typescript to the project and slowly converting some of our code to Typescript.

  • I’m Building An App – Step 3 – Security

    May 27th, 2019

    Is Validation Enough?

    Since my app is a serverless app, the validation performed on Step 2 is only client-side validation. While this does improve the user experience and helps prevent incorrect information from being entered into the app database, it does not protect against malicious attacks against my database.

    Client side security is not security.

    – some random person on Reddit

    The Conundrum

    We know that we need to do some validation/sanitization on the server side, but we don’t have a server. How is this possible?

    Enter Firebase Cloud Functions. From the Firebase docs:

    Cloud Functions for Firebase lets you automatically run backend code in response to events triggered by Firebase features and HTTPS requests. Your code is stored in Google’s cloud and runs in a managed environment. There’s no need to manage and scale your own servers.

    When I first read about Cloud Functions I actually imagined that you would write all of your code using a browser-based GUI or something; I was having a tough time determining how exactly you would write this server-side code. As it turns out, you write all of the code within your own app and then deploy it to Google’s servers.

    Let’s dive into it and figure it out.

    Add the NPM Module

    Importing the Cloud Functions module is pretty simple, it’s basically three terminal commands in your project folder:

    npm install -g firebase-tools
    firebase login
    firebase init functions
    

    After performing these steps, there will be a /functions/ folder in the root of the app. Within that folder’s /src/ folder will be an index.js file. This is where the Cloud Functions code will exist.

    The Code

    import * as functions from 'firebase-functions';
    const sanitizeHtml = require('sanitize-html');
    
    const sanitizeData = ( data:any ) => {
        return sanitizeHtml(data, {
            allowedTags: [],
            allowedAttributes: {}
        })
      }
    
    exports.onContactWrite = functions.database.ref(`users/{uid}/contacts/{id}`).onWrite( (change, context) => {
        const data = change.after.val()
        for (const prop in data) {
            data[prop] = sanitizeData(data[prop])
        }
        return change.after.ref.update(data)
      })
    
      exports.onMeWrite = functions.database.ref(`users/{uid}/me`).onWrite( (change, context) => {
        const data = change.after.val()
        for (const prop in data) {
            data[prop] = sanitizeData(data[prop])
        }
        return change.after.ref.update(data)
      })
    

    That’s pretty much it for that part. I may beef this up later as I learn more but this gets the job done. Data that is sent with HTML tags will get stripped out. Some examples:

    InputOutput
    <strong>Thomas</strong>Thomas
    alert(“pwned!”)ThomasThomas

    What About SQL Injections?

    Fair question. I have a database which means I need to protect against SQL Injection attacks, right? What are those, anyway?

    SQL injection is a code injection technique, used to attack data-driven applications, in which malicious SQL statements are inserted into an entry field for execution (e.g. to dump the database contents to the attacker).

    https://en.wikipedia.org/wiki/SQL_injection

    Actually, I don’t.

    The Firebase Realtime Database is a NoSQL database environment, meaning that as the developer you are not preparing SQL queries yourself and sending them to the server. Instead, you interact with functions provided by the Firebase codebase which then make writes/reads to the database.

    So, the short answer is nah.

    Database Permissions

    There is, however, a second layer to protecting data within your database, namely, authorization. Put simply, you need to set rules for how users can access and write the data in your database. If you don’t do this, anyone interacting with your app can modify any of the data in your database.

    We definitely don’t want that, so, let’s set up some rules. Thankfully, Firebase Realtime Database makes it easy to set some basic rules.

    Here’s pretty much as simple as it can get:

    {
      "rules": {
        "users": {
          "$uid": {
            ".read": "$uid === auth.uid",
            ".write": "$uid === auth.uid"
          }
        }  
      }
    }
    

    This means that within the data contained for a specific user(think back to the hierarchy of our data in the database), that user is only allowed to read and write their own data. Basically, when you are logged into your user account within my app(remember that Auth is powered by Firebase), you can only view and modify the data at or below your user account level.

    Larger, more complex apps will for sure need more stringent controls but in my case I think this is sufficient. Technically a user could change anything assigned to their user account which could pose a problem if you stored things like their user privileges, plan data, or renewal dates. If that’s the case, you don’t want people upping their privileges to Admin(if you have user roles) and you definitely don’t want someone changing their renewal date to 50 years from now and getting a free ride to use your app forever.

    For the purposes of this simple app, those very simple rules should work, though. As far as I can tell, the worst they could do is spam their own contact data with emojis so I’m fine with that.

    Do You Even Test Bro?

    You mean, have I written a unit test for this? Why yes, in fact I did, however, Unit Tests are part of Step 4. šŸ™‚

    Until next time.

  • I’m Building An App – Step 2 – Validation and UX

    May 23rd, 2019

    This is the fourth post in a series of posts which will illuminate my journey to becoming a Full-Stack JavaScript Developer. Read the first one here.

    Recap

    My plan is to progressively enhance the app into a fully complete app, allowing me to step-by-step learn important principles of development without overwhelming myself while at the same time practice my learning by applying them to a real app.

    Validation

    …data validation is the process of ensuring data have undergone data cleansing to ensure they have data quality, that is, that they are both correct and useful. It uses routines, often called “validation rules” “validation constraints” or “check routines”, that check for correctness, meaningfulness, and security of data that are input to the system.

    https://en.wikipedia.org/wiki/Data_validation

    Purpose

    Our app has a lot of fields that the user needs to interact with – not only do they need to login with an email and password, they need to register, reset their password, and add/modify contact information(name, birthday, email, etc).

    We can make the process of interacting with and submitting these fields more friendly and intuitive using validation. For the purposes of this post we’re talking about client-side validation. This encompasses checks that we add into the client-side(the app itself) which provide visual clues as to whether or not data is accurately entered.

    Library

    I previously used the Joi npm module for data validation in standard React web apps but for this one I decided to give yup a try. Yup is very similar to Joi but it claims to be smaller and a bit easier to use in projects.

    How it works

    Validation through yup works by creating schemas for your data which define rules for what your data should look like. Let’s take an example for the First Name field in my app.

    Schema

    const firstNameSchema = yup.string().required().min(2).max(15)

    This means that the “First Name” field should be:

    • A string(not an object, array, etc).
    • Required when submitting the form.
    • A minimum of two characters.
    • A maximum of fifteen characters.

    Validation

    The simplest form of validation is just calling the isValid() method on the schema object you defined and pass in the data you want to validate.

    firstNameSchema.isValid(text)

    In my app, whenever the text input changed for a field(when you started typing or deleting characters) the following would happen:

    1. A method named handleTextUpdate() would be called with the value of the text field(the text in the input field) and the prop passed.
    2. That method would update the corresponding piece of state with the new value of the text field.
    3. It would then call a method to validate that input field, passing in the prop name and the text.

    Full Code

    This is the JSX responsible for generating the First Name field:

    <TextInput 
      error={!this.state.isValidfirstName}
      prop="firstName"
      label="First Name" 
      placeholder={this.state.firstName}
      value={this.state.firstName}
      handleTextUpdate={this.handleTextUpdate}
    />

    When text is changed, this.handleTextUpdate is called.

    Gotcha: make sure to only write a reference to a function here, don’t include parentheses! Otherwise, the method will be called immediately upon load.

      handleTextUpdate = (text, prop) => {
        this.setState({[prop]: text})
        this.validateField(prop, text) 
      }

    This clever bit of code is responsible for handling all of the fields on the screen. The prop name is passed as a string. The text is implicitly passed. The reason [prop] is in brackets is because we want to pass the name of the prop. Read about how that works here.

    ValidateField method in full

      validateField = debounce ((prop, text) => {
          switch(prop) {
            case 'firstName':
                firstNameSchema.isValid(text)
                .then( (valid) => this.setState({ isValidfirstName: valid }))
                break
            case 'lastName':
                lastNameSchema.isValid(text)
                .then( (valid) => this.setState({ isValidlastName: valid }))
                break
            case 'address':
                addressSchema.isValid(text)
                .then( (valid) => this.setState({ isValidaddress: valid }))
                break
            case 'phone':
                phoneSchema.isValid(text)
                .then( (valid) => this.setState({ isValidphone: valid }))
                break
            case 'email':
                emailSchema.isValid(text)
                .then( (valid) => this.setState({ isValidemail: valid }))
                break
            default:
                break
          }
      }, 500)

    The debounce() before the method parameters is a lodash library function. What this does is prevents the method from being called immediately for every single text input change; it will wait 500 ms after the last call to the function before it actually invokes it.

    That might sound confusing at first so I’ll try to explain. When you type into a text field you want React to update state immediately without any delay. This is because the value of that field will be linked to state. You want that value to be “the truth” in the app and thus updated immediately and not prone to bugs or weird laggy behavior.

    I do not want validation performed immediately for every single keystroke, though; that would be taxing and annoying. So, instead, the app waits a half second after the user is done typing before the app validates the field.

    The debounce() function is great for search fields which automatically perform a search after you stop typing rather than requiring you to hit a submit button.

    Result

    My custom <TextInput> React component has a prop named error which is responsible for showing and hiding a small icon which is a visual indicator of pass/fail for validation.

    If validation fails, a red X icon appears next to the field; if validation passes, a green check-mark icon appears next to the field.

    That’s the gist of how I did validation throughout the app. I applied this same validation to the login form, registration form, and password reset form.

    UX Improvements

    Beyond validation, it’s a good idea when developing a mobile app to try to make entering data as easy as possible. You should dynamically change the keyboard type when possible to make it easier and enjoyable to enter data.

    Luckily, this is easily done without any extra libraries or validation; the core TextInput component that ships with React Native has tons of properties that can add hints as to how the field should be interacted with.

    The Phone Field

    <TextInput    
      textContentType="telephoneNumber"
    />

    The textContentType prop hints to the mobile device which type of keyboard to use.

    The Email Field

    <TextInput 
      autoCorrect={false}
      keyboardType="email-address"
      autoCapitalize='none'
      textContentType="emailAddress"
    />

    Here we have some hints that we should not allow autocorrect nor should we automatically capitalize the first letter of the text data. Note that we also have a slightly different keyboard than the standard keyboard(the @ symbol and the .com button).

    It can be tedious to go through documentation to find small little tweaks like this but it’s absolutely worth it to help make your app enjoyable to use as well as fast.

    Caveat

    I said earlier that this was all client-side validation. This does not make the app more secure. It only makes it less likely that users will make mistakes when inputting data as well as provides visual indication of the pass/fail condition of your validation functions.

    In the next blog post we’ll talk about server-side validation which improves the security of your app by preventing garbage and malicious input from being sent to your servers.

1 2
Next Page→

Website Powered by WordPress.com.

 

Loading Comments...
 

    • Follow Following
      • Thomas Shellberg
      • Already have a WordPress.com account? Log in now.
      • Thomas Shellberg
      • Edit Site
      • Follow Following
      • Sign up
      • Log in
      • Report this content
      • View site in Reader
      • Manage subscriptions
      • Collapse this bar