Allnomading (57)product (58)productivity (51)tech (23)thoughts (74)writing (71)

    Smithrandir, the Virtual Lab

    I’ve been releasing a lot of products over the last two years. About a dozen. Most have been abandoned. Five are still alive, all need love and attention. How can I prevent myself from reinventing the wheel each time I’m making a new digital product?

    I came to the conclusion I should view my products as atomic parts of a bigger entity. Each product I made so far is a monolithic LAMP application: PHP/Symfony with React DOM and MySQL.

    What I need to make things more modular and performant is to shift toward a micro-service architecture and leverage platforms like Netlify to decrease my hosting and development costs.

    I’ve been experimenting with GatsbyJS over the last two weeks, and I’ve fallen in love with how cutting-edge the technology is: my development time is significantly reduced, and the quality of the delivery increases proportionally. It’s perfect to manage all my front-end activities.

    Hosted on Netlify, I don’t have to spend time setting up SSL certificates or SEO or complicated DNS configurations, it just works right away, with built-in Continuous Delivery and Continous Integration directly from my Github repositories. And the best part is I don’t have to pay anything.

    I bought the domain name smithrandir.com, which is the primary domain that will host all my micro-services written in NodeJS. One micro-service will be served over one subdomain endpoint. For example, I have a websocket server I’m accessing at ws.smithrandir.com. This way, each micro-service can be reused in different products to decrease my server costs, and at the same time, I can manage them more efficiently.

    Then I just need to call my back-end services from my GatsbyJS websites using AJAX requests to dynamically render data.

    Shifting from PHP to NodeJS is a strategical choice. PHP is dying out but Javascript is not going to leave any time soon. Using GatsbyJS is also a door toward Progressive Web Apps.

    Slowly but surely, I’ll get to the point where I’ve built my own virtual lab.

    Training Routine for Programmer - Part 2

    In part 1 I’m discussing why I need to develop a training routine to become a better programmer. Part 2 is a draft containing notes describing solutions to the identified problems. Part 3 will be about defining micro-habits to perform on a daily basis.

    I. General Hygiene

    1. Equipment

    An Ergonomic Workstation helps prevent health issues:

    A) Increase your exposure to natural light, decrease night time work to avoid relying on artificial light sources.
    B) Sit on a comfortable chair with lumbar support and made of an airy fabric (no leather or hard surface, which tends to heat you up).
    C) Ergonomic keyboard and mouse reachable without stretching, no more than 20 degrees between your forearms and your tools.
    D) Ventilate your room.
    E) Screen positioned 50 cm from your eyes. Center of the monitor 20 degrees below eye level.

    2. Breaks

    A) Stand up and stretch every half-hour.
    B) Walk outside every three hours.
    C) Have lunch outside.
    D) Use a mindfulness bell.
    E) The 20/20/20 rule: after 20 minutes of computer work, look at an object about 20 feet away for about 20 seconds

    3. Evening routine

    A) Remove screens two hours before bed.
    B) Use an e-reader to read and take notes using a pen and a notebook.

    4. Proper diet

    A) Remove caffeine intake
    B) Fruits and nuts over junk snacks
    C) Plant-based diet

    5. Proper sleep hygiene

    A) Early afternoon nap if needed
    B) Go to bed when your body says so

    6. Social routine

    A) Go out to meet new people
    B) Call loved ones

    II. Conditioning

    1. Free weight exercise

    A) One hour after waking up.
    B) Program: StrongLifts 5x5
    C) Stretching
    D) Diaphragmatic breathing

    2. Typing exercises

    A) Practice typing on keybr.com

    3. Eye exercises

    A) Focus change, near and far focus, figure eight [4]
    B) Palming, blinking, zooming, shifting [5]
    C) The long swing, looking into the distance, exploring the periphery, sunning and skying [6]
    D) Peripheral vision training (sticks and straw exercise) [7]

    4. Hand-Eye Coordination

    A) Switching focus, play catch, juggle [8]

    5. Memory

    A) Learn the keyboard shortcuts of the Atom editor by heart, review every day
    B) Learn the keyboard shortcuts of the Kubuntu desktop by heart, review every day
    C) Read, take notes, convert them to mind-maps and memorize them
    D) Practice a foreign language every day and memorize 5 words/expressions per day
    E) Unplug the mouse, use only your keyboard (you only need a mouse when doing graphic design)

    6. Focus

    A) 10 minutes of seated meditation per day

    Bibliography

    1. The sacrifices we make to our health as programmers, Yoni Weisbrod, Hackernoon
    2. 10 Major Health Concerns For IT Professionals, Crisp360 Editors, Business Insider
    3. How to be a Healthy Programmer, Blazej Kosmowski, Selleo
    4. Eyes Exercises, Corinne O’Keefe Osborn, healthline
    5. Eye Exercises to Improve Eyesight, HDFCHealth
    6. 4 Powerful Eye Exercises for Rapidly Improving your Vision, Meir Schneider, Conscious Lifestyle Magazine
    7. Exercise Your Eyes to Increase Peripheral Vision for Athletics, Dr. Larry Lampert, Stack
    8. 3 Great Exercises To Improve Hand-Eye Coordination, Chiraine Rosina, We are Basket

    Training Routine for Programmers

    Heavily influenced by the way pianists exercise, I’m doing some research on how to become a better programmer by developing a training regimen.

    Exercising is a crucial part of a good work/life balance. Programming time is mainly spent hammering a keyboard: it’s a sedentary life with little physical movements.

    Bad physical health is synonym with heart disease, thrombosis, and cancer. More specifically, programming is associated with carpal tunnel syndrome (bad wrist posture), vitamin D deficiency (lack of sun exposure), bacterial infections (unkempt keyboards), stress (software development is stressful: crisis management, deadline pressure, computer usage), insomnia (blue light exposure), lower back pain (bad posture), and neck/eye strain (badly adjusted chair and monitor)

    Up until now, I never really thought about my health as a software engineer. I work out from time to time because I like the hormonal rush. What if I could align my workout routine with my aspirations as a maker? I’m pretty sure this would finally be a great reason for me to stay consistent with my visits to the gym.

    I’m going to write some notes on how I plan to help prevent the aforementioned health issues and improve my programming skills. From there I’ll establish a series of micro-habits I’ll follow over the next few months. If you’d like to tag along, maybe we can try to experiment with this regimen together.

    Master Programmer

    As a beginner developer, focusing on becoming a “10x engineer” is the wrong approach to get better at the craft of programming. You don’t want to produce ten times what other engineers do, you have to make your own path.

    An amazing programmer is a master programmer, a developer who can do great work. That’s our ideal: we may or may not reach it, the choice is ours to make every day. In software, you do great work by knowing how to learn how to code anything, with others. It’s about being capable of contributing to masterpieces.

    You don’t need to know everything by heart, but you can’t afford not to know how to obtain the information you need.

    As long as you know how to divide to conquer, you can do anything. Being able to break down a problem into smaller ones is the essence of programming. It implies a general understanding of the field and a deep comprehension of the overall problem at hand. Knowing what you need to know is 50% of the work.

    Programming is social. You collaborate with tons of people: other developers, end-users, copywriters, marketers… the list of stakeholders goes on and on. You want to make things for your own intellectual satisfaction, but never forget you mainly do it for others.

    Programming is incredibly diverse: from management and business to theoretical computer science, there is no one path you must adhere to. A good hacker follows her interests to benefit others. Just dare and make something personal.

    How to This: Share Feature

    User story: A user U can share a resource R owned by user O to a space S.

    Description: How can I can reproduce Facebook’s share feature?

    1. Relational database

    Table User_U: id

    Table Resource_R: id, fk_user_o_id (foreign key to user O)

    Table SharedResource_SR: id, fk_resource_id (foreign key to resource R), fk_user_u_id (foreign key to user U), fk_space_s_id (foreign key to space S), shared_at (datetime)

    Table Space_S: id

    Observations: We go with a denormalized schema. The data redundancy is quite small (a regular user shares a given resource in a space once or twice) so we will prefer increasing the Read performance.

    1. SCRUD functions

    Share a resource

    Requirements:

    1. A resource can be shared several times in a space. (interactions should be encouraged, spam can be handled by moderators)

    Pseudo-algorithm:

    1. Insert SharedResource_SR row

    Unshare a resource

    Requirements:

    1. Can’t unshare someone else’s shared resource.

    Pseudo-algorithm:

    1. delete the SharedResource_SR row by id where the fk_user_u_id field and the requesting user’s id correspond

    Get all resources shared in a given space

    SQL:

    SELECT r.id, IF(sr.fk_user_u_id = ‘{{user_id}}’, true, false) AS can_unshare FROM Resource_R as r JOIN SharedResource_SR AS sr ON sr.fk_resource_id = r.id WHERE sr.fk_space_s_id = ‘{{given space id}}’

    Observations:

    In this SQL statement we add a condition to tell the view whether or not the current user can Unshare a given text. If that’s the case, we will display an Unshare button when it’s appropriate.

    How to Write Product Requirements as an Indie Maker

    Requirement engineering is an entire subfield of software engineering, one that relies heavily on your communication skills: writing requirements is about defining your customers’ fundamental problems, goals, and needs, that will later be answered by a software system - a mobile app, a website, an application programming interface… a tech product.

    A requirement specifies the desired behavior of a product, which can either be functional (a task, what the product does) or non-functional (a quality/constraint, how the product does what it does).

    A requirement is always written from the point of view of a variety of stakeholders, which is why a certain quality is needed to make requirements easily understandable. This way, a stakeholder can agree on a set of requirements, as to avoid any unnecessary change down the road - which greatly increases the probability of a project’s success since changes are expensive.

    You elicitate requirements by talking with your users. It looks simple, but finding relevant users for your target segment is hard. It’s a maieutic process that takes skills.

    All requirements are documented in a central repository. In 200WaD’s case, it’s a public Trello board, but in big companies, it’s not unusual to use dedicated tools. Having a persistent common reference is incredibly important to ensure the project’s transparency and knowledge transfer.

    Requirements are put down on paper following a SMAR methodology: Simple - complete, unambiguous, understandable, atomic ; Measurable - traceable and verifiable ; Achievable ; Realistic - necessary and consistent. Different formats are possible: formal languages (programming language) and semi-formal languages (UML diagram…), but as indie makers we should always opt for natural languages (English).

    Natural languages are easily comprehensible for everyone, which comes at the cost of under-specification, fewer details can be described efficiently. This is why when you read Makerlog tasks, it’s really hard to understand what those mean and how they fit in the overall product.

    To solve this issue, we can find inspiration in a requirement engineering methodology known as GORE - Goal-Oriented Requirement Engineering. In this framework, requirements are directly linked to the overall goals of a software system - why it exists. Goals are decomposed into sub-goals, which are then tied to user stories.

    A user story is a well-known term in Agile project management describing a product’s atomic use case in a measurable fashion. User stories are high-level requirements in terms of abstraction. In my opinion, those are the molecular statements you want to log in your public accountability system: a card in Trello, or a task in Makerlog.

    User stories can then be decomposed in more technical tasks or constraints - checklists in Trello or individual commits in Git.

    Your public requirements must be written in a way your readers can easily understand, otherwise, they are useless to them:

    1. High-level requirements in the form of user stories
    2. Mention the project and the corresponding sub-goal: “Landing page redesign”, “Editor feature”, etc.
    3. Always write with clarity
    4. Diversify your tone: make it interesting and inspiring to read, not always formal.
    5. Use illustrations: emojis, pictures, anything helps really.
    6. Follow-up: don’t forget to explain and celebrate your product milestones next to your requirements. Makerlog has a dedicated feature exactly for that!
    7. Do not go too deep: low-level requirements belong to git commit messages or roadmap sub-lists - ie. “wrote function X in class Y”
    8. Do not be too broad: you need to be specific to be understood and to invite interactions.

    Programming software is a lot like writing when you start thinking about your end-users. Start improving today!

    Notes: Requirement Engineering, lecture 1

    Cornell notes from the Requirement Engineering lecture taught by Pr. Jelena Zdravkovic at Stockholm University (Lecture 1 - 2017)

    What is Requirement Engineering?

    It’s about capturing the customer’s fundamental problems/needs/goals.

    What is a requirement?

    It’s the expression of a desired behavior/condition of a system — what does it do? — without providing the solution (the design of the system will tell)

    What are the types of requirement?

    Functional (task) or non-functional (quality/constraints of the system) requirement.

    What are system stakeholders?

    A stakeholder is a person or organization involved in a given system.

    Why Requirement Engineering?

    Clear and complete statements of requirements for the stakeholders => improves sharing/communication => to avoid unnecessary changes and misunderstanding => increase the probability of a project’s success (requirement changes are expensive)

    When does Requirement Engineering happen?

    Software Dev Life Cycle (traditional): planning -> requirement definition -> design -> development -> integration/tests -> delivery/acceptance

    What are requirement artefacts?

    They are documented requirements : goals (desired states of the system), scenarios (examples of system usage), solution-oriented requirements ((non-)functional behaviors).

    How do we proceed?

    Requirement Engineering is a 5-phases process: Elicitation, Documentation, Negotiation, Validation, Management.

    What is the result of Requirement Engineering?

    A formal document (requirement document) including the artefacts.

    What is a specified requirement?

    A documented requirement following the specification rules of the project. There is no standard for requirement specification, unlike requirement documents e.g. IEEE or US Department of Defense.

    Why do we automate the Requirement Engineering support?

    To ease the structuration / management / update of many requirements.

    What are the main features of a Requirement Engineering support?

    Natural language requirement documents are converted in the requirement system (requirement database). The requirement system generates requirement/traceability reports.

    New Blog Engine

    I’m completely re-designing my personal website to develop my audience and my activities. I want to centralize all my online content and products in one place that feels personal.

    The hard thing about owning a website is not launching it, it’s keeping it updated.

    When someone types your name on Google, your personal website shows up first. It has to be the very reflection of who you are, what you stand for, and where you are headed. No one has time to hope around different social networks and tech products to see what you are up to: you are your best curator.

    Owing to those two last points, you want a custom website that can easily be refreshed.

    Instead of going for a heavy and cumbersome solution such as Wordpress, I went for a static website generator called Gatsby.js. The website is coded with Javascript (React framework), HTML, and CSS. The articles are written in Markdown. The whole app is then hosted on Github and deployed to Netlify for $0. All I need to pay is a domain name: $10 a year for BasileSamel.com.

    The main reason why I chose this tech stack is Continuous Integration. I just make a modification to my local Git repository and push it to the World Wide Web in a single command line. It’s never been easier (and cheaper) to update a home-made website.

    I don’t need to buy an additional web server because I can always redirect my users to another relevant service if I need them to interact with me. For example, I redirect them to Telegram to communicate, to Mailchimp to subscribe to my newsletter, or to Buy Me A Coffee to tip me.

    The simplest solution is usually the one you are going to keep around.

    On Distributing your Content - SEO

    Once you stop hiding you can finally start sharing your words with the world. That’s when your writings begin to affect reality, and when a new problem arises: you need to effectively distribute your content so that people are willing to hear you out.

    Marketing content is never simple. I’m not an expert, but I can tell you what I learned along the way.

    I started writing because it’s fun and I love it, but I kept doing it because I want to connect with people to build things together. To connect with more people, you need to share your content where it’s relevant.

    The most efficient and sustainable way to acquire an audience is through search engines - Google being the most important one. That’s where all the big recurring traffic is.

    The only issue is you need to rank well: people won’t find your article if you are located far away in the search results. That’s where the discipline known as Search Engine Optimization (aka SEO) comes in.

    The first thing you need is a single source of truth - a website where all your content originates from, from the search engine viewpoint. When you publish on Medium, all the search engine traffic goes to Medium, not to your personal brand.

    The single source of truth should always be something closely related to your personal brand: a personal blog, or your personal website. It’s really important for you to own this single source of truth, which is why it’s important for you to distribute your content on a dedicated blog you own.

    Copying the same content over several websites is known as “cross-posting”.

    When you publish on 200WaD, you can set up what’s known as a Canonical URL, which is used to indicate to Google where the original article is located. When a search engine robot encounters several times the same article - because it’s been cross-posted - it needs to assess where the original content comes from to know how to rank it in the search results. If your canonical URLs are not correctly set up, it will hurt your SEO, and thus your rank on Google: people will be less likely to read what you wrote.

    The strategy is thus to choose one place where all the content should be centralized - your personal blog - and cross-post this content everywhere (200WaD, Medium, specialized communities…), or just share it on social media.

    It doesn’t matter where you write first. What matters is to correctly adjust the canonical URL to point to your blog.

    Of course, SEO is a large field. Canonical URLs are just the tip of the iceberg. In the next post, I will talk about backlinks and HTML.

    Something is gonna go wrong

    I released new code yesterday and as usual stuff breaks. Something is always going to go wrong: broken features, change-averse users, unhandled edge cases… danger is everywhere.

    A launch is not just one moment in time, it’s a cycle. And the more you go through the cycle, the harder it gets to overcome Launch Resistance - the fear of breaking stuff that used to work.

    Move fast and break things. Developers hear it a lot, and yet, there is always a lingering fear that things won’t work out the way you want them to. They rarely do.

    I broke a core feature of the website: the writing editor. You can whine and hide, or you can fix it. I chose the latter and released a fix in one day of work. Will it matter in six months? No, so why should I care now? I learned more in one day of breaking and fixing things than in one day of preparing things.

    Breaking things is taboo in the engineering world. In school, we are told we need to handle all the use cases, to prepare for every possibility, that we need to be perfect. There is no such thing as perfection in this world, and if it does, it will kill your soul.

    As a maker, you can’t afford to lose time. Never forget you work WITH users, not just FOR them. Throw stuff at them and they will tell you what they like and what they don’t. That’s how you fix and improve things at the same time.

    What about Unit Testing then? It’s important indeed, but never forget you can’t prove the absence of bugs, so don’t spend too much time testing things programmatically. Confront yourself to reality.

    Thanks to all my users for the support, and don’t hesitate to ping me if I can help you with anything.

    Notes on

    1. Accessing Text Corpora

    1.1 Gutenberg Corpus

    What is a corpora?

    A large structured collection of texts.

    How to get the text list of a corpus?

    corpus.fileids()

    How to access a default corpus in NLTK?

    from nltk.corpus import gutenberg
    nltk.corpus.gutenberg.words('austen-emma.txt')

    How to obtain the content of a file without any linguistic processing (not split up into tokens)?

    gutenberg.raw(fileid)

    How to divide the text up into its sentences?

    gutenberg.sents('shakespeare-macbeth.txt')

    1.2 Web and Chat Text

    How to access default web texts in NLTK?

    from nltk.corpus import webtext

    How to access default chat conversations in nltk?

    from nltk.corpus import nps_chat
    chatroom = nps_chat.posts('10-19-20s_706posts.xml')

    1.3 Brown Corpus

    What is stylistics?

    The study of systematic differences between genres. Word counts might distinguish genres: the most frequent modal in the ‘news’ genre is ‘will’, while the most frequent modal in the ‘romance’ genre is ‘could’.

    What is the Brown Corpus?

    A convenient resource for studying systematic differences between genres:

    from nltk.corpus import brown

    1.4 Reuters Corpus

    What is the Reuters Corpus?

    For training and testing algorithms that automatically detect the topic of a document. Text categories in the Reuters corpus overlap with each other.

    from nltk.corpus import reuters

    1.5 Inaugural Address Corpus

    What is the Inaugural Address Corpus?

    A temporal corpus representing language uses over time.

    from nltk.corpus import inaugural

    1.6 Annotated Text Corpora

    How to get a list of all NLTK corpus?

    Visit http://nltk.org/data

    1.7 Corpora in Other Languages

    Universal Declaration of Human Rights in over 300 languages

    from nltk.corpus import udhr

    1.8 Text Corpus Structure

    How to access the categories of a corpus?

    corpus.categories()

    How to list the words contained in the corpus?

    corpus.words()

    1.9 Loading your own Corpus

    How to load your own Corpus?

    from nltk.corpus import PlaintextCorpusReader
    corpus_root = '/usr/share/dict'
    wordlists = PlaintextCorpusReader(corpus_root, '.*')

    OR

    from nltk.corpus import BracketParseCorpusReader
    corpus_root = r'C:\corpora\penntreebank\parsed\mrg\wsj'
    file_pattern = r'.*/wsj_.*\.mrg'
    ptb = BracketParseCorpusReader(corpus_root, file_pattern)

    Moving off Slack

    As some of you might know I’m currently developing an integrated chat within 200WaD. I want members to write more together, so a chat gathering everyone is a must-have.

    Slack is a bit cumbersome to use: you have to install it, configure your account, and actually write/check messages. Not everyone has used Slack before, and I can’t expect everyone here to sign up.

    However, we all subscribed to 200 Words a Day. That’s where the magic should happen.

    At first I wanted to integrate Slack within 200WaD using their Application Programming Interface, but it turns out I made a mistake: I didn’t read the f* API rate limit. I spent three days building something that will be unusable given our desired use - about 1000 visitors per day versus a one websocket connection per minute limit: unthinkable.

    I could have bypassed the rate limit by setting up a middleware (a server making requests instead of a user), but it’s more complex than rolling out our own in-house chat server from a structural point of view. That’s why today I decided to completely move off Slack and build my own chat engine.

    Another reason I want to have total control over the chat application is the Writing Circles feature: the possibility for 200WaD members to create groups based on common interests, which in turn could become a possible way to monetize 200WaD using a B2B business model.

    200WaD is driven by one purpose: empowering writers. And I believe building a free open community based on collaboration to be the way to go about it. Building a chat to remove all communication barriers (= messages lesser than 200 words) is the first step towards this vision.

    Integrating Slack in a Website

    Instant communication channels have been around for a long time. Their business value cannot be ignored: you can build entire communities from a chat application. Telegram, Slack, or Discord have become mainstream tools in most organizations.

    Relying on free external services has its limits though, most users do not want to install anything or create an additional account. It’s especially true for tech products such as web applications: it’s already hard to convince a user to use your product, why would he/she want to subscribe to another service within it? It feels redundant, it’s not practical.

    On the other hand, implementing a chat application is no trivial task. The user interface quickly gets out of hand, messages must be loaded in near real-time, you need to keep track of the user presence, messages must be stored… it’s an entirely different area of expertise that comes with heavy operational costs.

    That’s where the chat integration comes in, it allows you to get the best of both worlds: less coupling in your infrastructure, better features, and more importantly, increased interactions between your users.

    To give you a concrete example, 200 Words a Day is an online community based on its own website. Soon after the minimum viable product phase I decided to establish a Slack workspace in parallel, to interact with the members in a different way. Out of the 2800 members who registered on the platform, 130+ users joined the Slack workspace. That’s only a 5% conversion rate.

    Progressively moving off Slack appeared as the most straight-forward way to increase interactions between members. The issue is I don’t want to build a chat app from scratch. I tried already in a previous project and it wasn’t easy. I do not want to increase my server costs either. The best approach was to use Slack’s API to create a client within 200WaD. This way, users who didn’t registered in Slack can still read what’s going on, which in turn should result in a higher conversion rate.

    1. Installing a Slack App

    Log in Slack and head to api.slack.com/apps to create your Slack client. You will need a workspace ready with admin rights.

    Once the app has been set up, you obtain a Client ID and a Client Secret.

    SLACK_CLIENT_ID=XXXXX<br></br>SLACK_CLIENT_SECRET=XXXXX

    Add a bot user by clicking on the “Bot Users” tab in the left menu.

    Navigate to the “OAuth & Permissions” page of your Slack application to add some permission scopes. Let’s start with channels:history, channels:read, chat:write:user, groups:history, groups:read, incoming-webhook, bot, users:read, and users:read:email. Those scopes will allow us to write and read from/to public and private channels. Save the changes and hit “Install App to Workspace”.

    You will be prompted to a confirmation page. Choose any channel to confirm the installation - it doesn’t matter which one - and click “Install”.

    You are redirected to the OAuth & Permissions page. Copy both your OAuth Access Token and your Bot User OAuth Access Token.

    SLACK_OAUTH_ACCESS_TOKEN=xoxp-XXXXXXXX<br></br>SLACK_BOT_OAUTH_ACCESS_TOKEN=xoxb-XXXXX

    You just need to configure one thing in the same page: a redirect URL. The Redirect URL is used in the login process, it’s usually the URL you use to enter your chat application from within your website. For example, my local environment uses http://localhost:8000/chats, but I have another Redirect URL (https://200wordsaday.com/chats) in my production environment. Add both and save the parameters.

    You now have a client ready to interact with your Slack workspace.

    1. Implementing a Slack Client

    A. Storing and Syncing Users

    In order for your visitors to write to your Slack client, they need to be authenticated.

    Slack users are described by a unique identification number attached to their Slack account, and they can read/write from/to the Slack workspace by using a personal access token. Ideally, you want the authentication process to be as painless as possible: authenticate once, store the user access token and identification number in your web app database, and use them whenever it’s needed.

    Chances are your web app and your Slack workspace have two distinct sets of members: you need to synchronize the two user bases by using the identification number. You can for example query users based on the ids you receive, then request the email addresses to match them with the ones stored in your own database. This way your application can understand who is who based on the Slack identification number.

    Sometimes the emails do not match. A user might want to use a different email address for example. Email matching is a trick to pre-populate your database, but you still need your user to authenticate from within your app.

    That’s where the “Sign in with Slack” button comes in. It’s the only way for your user to interact with your Slack client.

    B. Sign in with Slack

    The ”Sign in with Slack” button allows your user to authenticate: to access direct messages, private channels, and write messages.

    When a user arrives to your web chat page - represented by the Redirect URL we configured in part 1 (ie localhost:8000/chats) - we need to fetch an access token to communicate with Slack’s APIs. Clicking on the Sign in with Slack button redirects the user to a authentication page, which returns data about the users to your web application: the user identification number, and the access token.

    You can retrieve them once and store them in your database for further use.

    Of course, before signing in, a user must have an account in your workspace. If that’s not the case, you can display an invite link to register new members.

    After logging in Slack, the user is redirected to your web application along with an authentication code parameter as a GET variable, according to the Redirect URL you specified.

    You can exchange this authentication code for an access token by calling the oauth.access endpoint of the Slack API:

    public function authenticate($code){<br></br>    return $this->get("https://slack.com/api/oauth.access", array(<br></br>        'client_id' => getenv("SLACK_CLIENT_ID"),<br></br>        'client_secret' => getenv("SLACK_CLIENT_SECRET"),<br></br>        'code' => $code,<br></br>        'redirect_uri' => 'http://' . getenv('HOST') . '/chats'<br></br>    ));<br></br>}<br></br><br></br>$response = $this->authenticate($code);<br></br>echo $response['access_token']; // => your user's access token<br></br>echo $response['user']['id']; // => Slack user id<br></br>

    The user is now able to use Slack’s APIs.

    C. Understanding Slack’s APIs

    Slack’s Application Programming Interface is in fact a set of several atomic APIs: Web API, Events API, Conversations API, and Real Time Messaging (RTC) API.

    In this tutorial, we are going to use all of them to implement specific features.

    The Web API is used to send rich messages. Not just text, but also pictures, links and file attachments.

    The Events API is used to be notified when you receive direct messages.

    The Conversations API allows us to access the message history of any channel or private conversation.

    The RTC API is a websocket-based API used to know which users are online. Its main purpose is to receive channel messages in near real-time. It complements the Events API to notify our application of anything happening in our Slack workspace.

    1. Main Features

    A. Listing Conversations

    There are four conversation types: public channels, private channels, group conversations, and direct conversations.

    Channels have no theorical user limit. A group conversation (mpim) can gather 9 users top. A direct conversation (direct message, im) is between two users.

    All you need to retrieve the list of conversations is to call the API endpoint conversations.list:

    $conversations = $this->get("https://slack.com/api/conversations.list", array(<br></br>    'token' => $this->getToken($user), // (1)<br></br>    'types' => $types, // (2)<br></br>    'exclude_archived' => true // (3)<br></br>));<br></br>

    (1): If your user is not authenticated, use your own app oauth access token. Else, let the client uses his/her own.

    private function getToken($user){<br></br>    $token = getenv("SLACK_OAUTH_ACCESS_TOKEN");<br></br>    if($user->isAuthenticated())){<br></br>        $token = $user->getSlackAccount()->getToken();<br></br>    }<br></br>    return $token;<br></br>}

    (2): If your user is authenticated in your web client you can display all the related conversations. Otherwise, you just want to fetch public conversations. This is what the $types variable specifies:

    $types = 'public_channel';<br></br>if($user->isAuthenticated()){<br></br>    $types = 'public_channel,private_channel,mpim,im';<br></br>}

    (3): Set to true to exclude archived channels

    Slack then returns a list of conversations we can use to read or send messages.

    B. Retrieving messages of a given conversation

    C. Retrieving members of the workspace

    D. Formatting messages

    E. Sending messages

    F. Receiving messages in real-time

    G. User presence

    Where I'm heading to, technology-wise

    I talk a lot about my projects and my day-to-day life as a nomad entrepreneur, but not so much about my skills as a software engineer. I decided to flip this behavior by starting to release more technical content.

    My current stack is Symfony (PHP) on the back-end and JQuery/Twig/Bootstrap on the front-end.

    I got into Symfony because that’s the framework I had to work with at my first job, and since I have a more back-end background I never got into front-end frameworks and just tweaked my apps with some JQuery.

    Symfony is a MVC framework, so I don’t really feel like changing it. PHP is a popular language that keeps on getting better, and Symfony is similar to Laravel in terms of architecture and performance. Twig is also an incredible template engine.

    I’m slowly taking on React to replace JQuery. It’s 2019 and I’m starting to build DOM-intensive projects. React appeared as the most marketable skill I could take on as of today.

    I don’t want to waste the five years I spent studying calculus in engineering, so I’m also taking on new courses in applied Machine Learning, more specifically in Natural Language Processing. I studied basic Machine Learning during my last year in college and I absolutely love the topic! It’s amazing to see all the things you can do with it, and it’s giving me so many ideas to help writers at 200WaD: we could create our own minimalistic Hemingway App or Grammarly, the possibilities are unlimited and it’s beyond exciting!

    In parallel, I’m also taking on new tools to increase my code quality. For example, I’m studying ways to improve my Git workflow and to install Continuous Improvement/Continuous Delivery services.

    This is basically where I’m heading to over the next year.

    Teaching People How to Program

    I got into programming as an autodidact, I ended up graduating from college with a major in software. Both formal and informal education has pros and cons.

    Autodidactism fueled my drive, it’s what got me hooked to the craft.

    Engineering school taught me the basics, how each concept fits together. More importantly, how software quality is defined and evaluated - which is what makes you an initiate, a professional.

    Formal education is no longer a necessity to work in most companies. Its most essential aspects can be replaced by personal practice, books, online courses, or support communities.

    Learning how to program is half learning how to code, half learning how to optimize your code for humans and machines to process it. Once you understand that, it’s clear learning how to program is a quest for quality, an artisan apprenticeship. Consequently, programming is a search for the highest quality: beauty.

    You need to master many tools and concepts in order to reach this level of mastery. Each technology you learn serves this purpose. For example, you don’t do versioning because everyone does it, you do versioning because development is teamwork and versioning addresses the challenges that come with a collaborative environment. The mantra of the software developer is continuous improvement.

    When you start learning karate, you probably expect to kick some people’s butt during your first training session. Of course, that’s not how it works: you need the basics first, otherwise, you just end up hurting yourself. More importantly, you need the underlying philosophy - to understand it’s not okay to use your powers against the very rules your practice is based on: pacifism in karate (undoing and avoiding violence), or excelsior in programming. Now we understand what programming is about, we can proceed to learn the basics.

    We all seek knowledge because we are expecting something from it. The way you learn must reflect the inner reason why you got started in the first place. Learning is thus a constant shift between a macroscopic (the end goal, the bigger picture) and a microscopic (an atomic element of knowledge) scale. Depending on where you stand, you need to take a pragmatic (tutorial) or a theoretical (compendium) approach, or something in between (handbook). The quicker you strike a balance between the two, the faster you can start developing a “passion” for the subject - because you created an action/reward loop.

    One thing to understand about programming is that the language rarely matters. PHP, Javascript, Java, Python, Ruby… spending too much time wondering which choice is better is futile. The reason is quite simple: most “mainstream” languages follow the same paradigm mixing imperative and object-oriented programming. Once you understand a concept in one language it becomes easy to adapt it to another. It’s true for basic elements of programming - loop structures, conditional statements, etc. - but also for more advanced and subtle concepts, such as design patterns explaining how good software is structured: if you know how to use one MVC framework (Symfony), you can quickly grasp the inner workings of similar tools (Laravel, Ruby on Rails…).

    … to be continued

    Notes on

    1. Computing with Language: Texts and Words

    1.1 Getting Started with Python

    1.2 Getting Started with NLTK

    How to download corpora?

    import nltk
    nltk.download()

    How to load corpora?

    from nltk.book import *

    1.3 Searching Text

    What is a concordance view?
    A concordance view displays every occurrence of a given word in its context (= preceding and following words).

    string.concordance('word')

    What other words appear in a similar range of contexts?

    text.similar('word')

    How to examine shared contexts between words?

    text.common_contexts(['word', 'writer'])

    What’s a dispersion plot? How to obtain it?
    A dispersion plot displays the locations of a word in the text,
    each stripe represents an instance of a word.

    text.dispersion_plot(['citizens', 'democracy', 'freedom', 'duties', 'America'])

    1.4 Counting Vocabulary

    What’s a token?
    A sequence of characters: a word and/or a punctuation symbol.

    How to obtain the number of tokens?

    len(text)

    What’s the vocabulary of a text?
    A vocabulary is the set of tokens contained in a text.

    set(text)

    How to sort an array in Python?

    sorted(array)

    What’s a word type?
    A word considered to be an unique item within a given vocabulary.

    How do you quantify the lexical richness of a text?
    Divide the number of distinct words over the total number of words. The result is a percentage of distincts words.

    len(set(text)) / len(text)

    How to count occurrences of a specific word within a text?

    text.count('word')

    How to create a function in Python?

    def function_x(param):
       return true
    1. A Closer Look at Python: Texts as Lists of Words

    2.1 Lists

    How to create a list in Python?

    [‘’, ‘’ etc.]

    How to concatenate lists in Python?

    [ ] + [ ]

    How to append an element to a list in Python?

    list.append(element)

    2.2 Indexing lists

    What’s an index?
    It’s the position of an item inside an array/list.

    How to access an index from a value?

    text.index(value)

    How to access a value given an index?

    text[index]

    What is slicing?
    It’s retrieving a subpart of an array/list.

    text[index1:index2] ; text[index1:] ; text[:index2]

    2.3 Variables

    2.4 Strings

    What’s a string?
    Strings are lists of characters, so a string shares the same properties than a list.

    How to convert a list to a string?

    ' '.join(list)

    How to convert a string to a list?

    string.split()
    1. Computing with Language: Simple Statistics

    3.1 Frequency Distributions

    What is a frequency distribution?
    It’s a matrix where each row represents the frequency of a vocabulary item in a given text.

    fdist = FreqDist(text)

    How to get the most frequent tokens?

    fdist.most_common(<number of tokens to get>)

    How to obtain a cumulative frequency plot?
    A cumulative frequency plot tells us what proportion of a text is taken by the most common tokens:

    fdist.plot(50, cumulative=True)

    What’s an hapaxe?
    An hapaxe is word that occur only once in a text. Hapaxes are considered as outliers in data analysis, and thus not generally useful.

    fdist.hapaxes()

    3.2 Fine-grained Selection of Words

    How to operate a fine-grained word selection by word length and frequency?
    Obtain words which are at least 7 character long and that appear at least 7 times in the text:

    w for w in set(text) if len(w) > 7 and fdist[w] > 7

    The result is useful to identify key words in a text content-wise.

    3.3 Collocations and Bigrams

    What’s a bigram?
    A pair of words.

    list(bigrams(['more', 'is', 'said', 'than', 'done']))

    What is a collocation?
    A sequence of words that occur together unusually often, and which are resistant to substitution with words that have similar meanings. A collocation is a frequent bigram.

    text.collocations()

    3.4 Counting Other Things

    How to get the frequency distribution of the different word lengths?

    fdist = FreqDist(len(w) for w in text)

    How to obtain the max value in a list?

    fdist.max()

    How to access a given frequency in a frequency distribution?

    fdist.freq(frequency_index)
    1. Back to Python: making decisions and taking control

    How to create an if statement in Python?

    if len(word) < 5:
    ...    print('word length is less than 5')
    elif token.istitle():
    ...     print(token, 'is a titlecase word')
    else:
    ...     print(token, 'is punctuation')

    How to create a loop in Python?

    for word in ['Call', 'me', 'Ishmael', '.']:
    ...    print(word)

    How to operate on every element of a loop?

    [function(w) for w in text]
    1. Automatic Natural Language Understanding

    What is Word Sense Disambiguation?
    It’s an area of NLP where we want to discover the intended meaning of a word in a given context.

    What is Pronoun Resolution
    It’s about detecting the subjects and objects of verbs, finding the antecedents of a word.

    What is Anaphora Resolution?
    It’s a part of pronoun resolution where we identify what a pronoun or noun refers to.

    What is Semantic Role Labeling?
    It’s about identifying how a noun relates to the verb. Also a part of Pronoun Resolution.

    What is Text Alignment?
    It’s a program automatically pairing up sentences. Once we have a million or more sentence pairs, we can detect corresponding words and phrases, and build a model that can be used for translating new text for example.

    What is a Spoken Dialogue System?
    It’s a pipeline of language understanding components to generate a speech answer to an audio question.

    What is RTE (Recognizing Textual Entailment)?
    It’s a challenge in language understanding where you try to automatically verify an hypothesis from statements given previously.

    Releasing a Markdown editor tomorrow

    I’ve been thinking a lot about how to improve my writing process and using a markdown editor definitely helps with that.

    I used markdown to take notes in college, to present projects on Github, and more lately to write an ebook.

    Markdown is a plain text language, so it’s easier to focus on the substance over the form while writing. It’s also simpler to import/export and share across many platforms.

    The second advantage of Markdown is how it goes well with versioning. You can store all your different writing drafts in a Github/Gitlab/[…] account and never lose anything ever again.

    It’s obviously an incredible tool to help writers focus on what really matters: the message, the art, rather than spending time on formatting.

    This is why today I started working on an optional Markdown editor for 200 Words a Day, and the minimum viable version should be up tomorrow (I’m testing it as of now). It wasn’t easy but I know many writers want this feature.

    I’m particularly excited about the possibility to write more technical articles. I’ve been interested in writing about programming from an entrepreneurial point of view for a long time, and I believe it would be nice to share more of what I know.

    The Maker Economy: Learn to Code

    The No-Code Movement has its advantages: you can build minimum viable products and proofs of concept in minutes for free, and no-code development platforms are incredibly easy to use. Making a personal website or manipulating databases have become common tasks where programming creativity is not inherently fundamental. Reinventing the wheel is overkill in those use cases, and not everyone is interested in learning how to code. Generally speaking, no-code tools are for people willing to outsource all coding activities.

    If you’re a tech maker, however, learning how to program will give you tremendous entrepreneurial powers. Notice I wrote “learning how to program”, and not “learning how to code”. Anyone can code, but programming takes a lot of tacit knowledge.

    Each piece of code is a brick: you can stack code together to obtain a wall, a program. There are many ways to build a wall. Some will resist the strong winds, some will collapse at the first breeze. Programming is the craft of building sustainable programs, for machines and humans alike.

    And this is precisely the huge difference between home-made quality software and no-code tools: the former is built with both sustainability and customizability in mind, its essence is organic.

    Of course, the learning curve to master a no-code tool is way smoother, because you sacrifice several benefits of making things yourself.

    Coding stuff yourself is cheap: you can start running a startup with a few bucks. All you need is a domain name, some elbow grease, sometimes a web server, and you are set. You trade time for money and knowledge. I started monetizing 200 Words a Day along with three other websites for $20 a month. Bubble for professional use starts at $62 per month. Wix for businesses starts at $18 per month, but you also have to get yourself a bank account, pay for a domain name, and you are limited to one website.

    Programming is becoming independent. The more you rely on external companies to help you, the more restricted you are: a tightly-coupled solution cannot work by itself, by definition. If your solution provider is experiencing a breakdown or decides to raise its price, you are at its mercy. Using development tools is a creative trade-off: you can choose the design template you like, but you are still limited. The appeal of creative freedom is what got me into learning some code in the first place: I was a 13-year-old teenager who loved joining role-play phpBB forums, and I wanted to build my own forum. I started with phpBB forum generators. I quickly felt limited by the built-in parameters so I decided to learn how to make a website.

    Learning enables social aggregation. All successful tech entrepreneurs belong to one or several tribes because humans are inherently social: indie hackers, YC alumni, makers… we all need labels to strive. On the other hand, sharing and contributing is inherent to programming: what you learn is content you can distribute. Knowledge commands respect and recognition, learning how to program is thus a way to develop your network. From an entrepreneurial point of view, developers are extremely interesting because they are educated early-adopters, not afraid - sometimes excited - of trying out new technologies to give valuable feedback.

    I’ve always been excited about science fiction and all the possibilities offered by software. Artificial intelligence, web development, cybernetics… the field is just so versatile. Boredom appears impossible. Learning how to program is not just any skill, you are not simply learning how to paint a wall, it’s a set of highly marketable skills you can get paid for. All industries are impacted by digitalization and programming gives you access to these new opportunities. If you love dancing, you can build your own platform to showcase your salsa skills, to create your own brand, or to become a virtual teacher. You can stay at home to take care of your kids or sick parents, or travel the world as a digital nomad, while still interacting with customers worldwide. The declensions are infinite depending on your own interests. Learning how to program becomes more than a skill, it’s liberating, it becomes an integral part of your lifestyle.

    Economies of scale appear when you become a more experienced programmer. Everything you code should be modular, meaning, capable of working on its own but easy to integrate. If you respect this principle, all code is reusable. If you program a blog engine once, you don’t need to code its features again. You can reinject each feature in new projects. Code quality is built by iteration, just like a craftsman learns to forge better swords by learning from his shortcomings and improving over the previous ones, except that with code you can reuse the base materials ad eternam. The resulting boilerplates skyrocket your productivity, and that’s how you become a prolific maker: by constantly recycling and improving. On the contrary, reusability is quite restricted when it comes to using no-code tools.

    For makers, building a hundred different web applications is quicker with code because your execution skills grow exponentially when you start programming things yourself. And we all know your speed of execution on the long-term is what really matters in the entrepreneurial game.

    Redesigning my Personal Website

    My personal website is not well-kept, its potential is untapped. My motives changed a lot in one year, my online domain should reflect those.

    My current goal is to reach ramen profitability. At $1000 per month, I need 500 people to buy a $2 product from me. I have three income sources at the moment: my 200 Words a Day patrons (90% of my total revenues), the revenues from my ebook (10%), and my new Patreon account (0%, not launched). The objective is to design the flow of the website to convince people to help me help them.

    You need three things to persuade someone online: added value, utmost transparency, and good copywriting.

    I add value by investing my time in the development of important web products and by sharing what I learn in my daily writings. I also use social proofs to make my personality stand out.

    I become transparent by openly reporting my goals, my values, and my metrics (costs/revenues breakdowns, daily active users…). I stay open and accessible.

    Finally, I need stellar copywriting. Most portfolio websites feel generic and bland, but my focus is on inspiring the reader. To do so I follow a Golden Circle structure emphasizing the pain points I’m trying to address through my work. I’m pretty enthusiastic about the first principle approach to problem-solving.

    This new website should be up tomorrow.

    Minimalist Project Management

    My workflow is pretty simple: I write everything down. Sometimes in blog posts or in tweets, mostly in logging applications and lists. I know everything I’ve delivered over the past 160 days up to the minute.

    At the operational level, my to-do lists are centralized in different Trello boards. One per project, including 200WaD. Most boards are organized in a Kanban fashion (to do/on-going/done).

    Project management is an effort at improving organizational communication flows. Communication is both cause and consequence.

    All the feedback I receive from my stakeholders through email, Telegram, Slack, or Twitter is logged in to-do lists along with a username so that I can follow-up on them once I deliver.

    Every task you accomplish in your day-to-day work is an opportunity to share. This is why I log everything across different applications: Makerlog for real-time logging, Twitter for daily reports, Trello for public accountability, and Github for collaborative work.

    Transparency and consistency are the pillars of efficient communication because they generate trust: project management resources must stay easily accessible, dead simple, and regularly updated. I have no sophisticated quality process, only an artisan’s mindset.

    There is no strategic level either, at least for now. Only a quest for better products.

    Software, my Love

    I started programming at 13 to build my own role-playing game forum engine in PHP. I failed, but the magic of software stayed with me and I wanted to become a software engineer. I am fortunate I didn’t discover programming through the prism of formal education. I had an issue to solve, coding was the solution: it wasn’t forced on me, it came to me.

    A program is a bag of instructions transforming an input into a worthwhile output. Software allows us to represent knowledge in a different way, sometimes more efficiently, to access it or distribute it. The beauty of software resides in its educational purpose. Education comes from “ex-ducere”, meaning, “to guide”, toward what’s outside. Software is an opportunity for growth, an opportunity to transcend, the ability to help others access a higher level of comfort - freedom from pain.

    And this is why I find programming so beautiful. A vision of pure creation. A language coming to life to bend reality.

    Humans have a tendency to disenchant the world. If I had to convince someone to study software engineering, I wouldn’t define it as pure engineering. Instead, I would emphasize its creative yet practical aspect. Being a great software engineer is being an innovative problem solver.

    Toward an art of software development

    What is art? Technical mastery, innovation, expression, beauty. Those are the words that come to mind. Art is about emotions, not rationality. About how it makes you feel, rather than how well it works.

    In The Pragmatic Programmer, Andy Hunt and Dave Thomas say: “the construction of software should be an engineering discipline”, but that “it doesn’t preclude individual craftsmanship”. It is assumed by many that software development is purely an engineering discipline.

    I do not agree.

    “Art” comes from the Ancient Greek word “Techně”, which implies the technical mastery of a craft. It is quite incredible to understand that artists were in fact, at first, artisans. The border between craftsmanship and art is thin: an artist was someone able to perform a given work at a higher quality level than others. Excellence was the criteria. Artisanal products (such as textiles) could be perceived as much more precious than paintings or sculptures. In a sense, any artisan can become an artist.

    On the other hand, the meaning of a word is tied to its historical context, so defining art from its etymology might be self-limiting. Let’s have a look at another approach.

    In his book Living with Art, Mark Getlein proposes six functions of contemporary artists:

    1) Create places for some human purpose

    2) Create extraordinary versions of ordinary objects

    3) Record and commemorate

    4) Give tangible form to the unknown

    5) Give tangible form to feelings

    6) Refresh our vision and help see the world in new ways

    I could make parallels with software for each point above. My key takeaway is that art is about communicating ideas and storing information as well. Roman artists made sculptures of emperors to “store” this information and allow them to access immortality in some way. Art is something you interact with. Not only physically.

    Similarly, software aesthetics exists. Paul Graham says it better than anyone:

    Hackers, likewise, can learn to program by looking at good programs […] paintings are created by gradual refinement […] Great software, likewise, requires a fanatical devotion to beauty. If you look inside good software, you find that parts no one is ever supposed to see are beautiful too. […] It drives me crazy to see code that’s badly indented, or that uses ugly variable names. […] Most makers make things for a human audience. And to engage an audience you have to understand what they need. Nearly all the greatest paintings are paintings of people, for example, because people are what people are interested in.

    I can see many parallels between the Maker movement and how artisans reached the artist status in the first place.

    Craftsmen belong to guilds. Artists have patrons.

    Engineers belong to companies. Makers strive to live from their own products.

    Software development has reached a stage where it is not necessary to be part of a company to make tech products.

    Hackers are breaking pre-established rules and express themselves throughout their own form of expression. Just like great artists use art as a catharsis, makers create products to solve their own problems.

    Companies become either increasingly atomic or increasingly big. There is less and less in-between.

    Artists ship,” says Steve Jobs. So do makers.

    So while I admit that hacking doesn’t seem as cool as painting now, we should remember that painting itself didn’t seem as cool in its glory days as it does now.

    Paul Graham

    In Ancient Greece, each art form was personified by a Muse. Nine Muses, but none to represent painting and sculpture.

    Sculptors and painters were held in low regard, somewhere between freemen and slaves, their work regarded as mere manual labor.

    In Our Time: The Artist BBC Radio 4, TX 28 March 2002

    Sounds familiar?

    What if, instead of marketing software development as a pure engineering practice, we promoted it as an art?

    Could it inspire a whole new generation of product-oriented programmers willing to solve important problems?

    Developers, start creating. Don’t fall into elitism, but be proud of your job. Because maybe one day, the future generations will be able to look at us and see pioneers of a software art.

    There is no worthless app

    Oscar Wilde famously said that all art is quite useless.

    Similarly, one could argue that all apps are useless, meaning, they are not needed to live.

    And this is a peculiar argument which I think is the reason why so many makers never launch or never go through with their ideas. A fear of uselessness.

    But being useless is not the same thing as being worthless.

    Making an app can only benefit you in the long term.

    Your market value is all about your capacity for learning hard materials fast and creating at an elite level, in both speed and quality. Making is about both.

    Apps are either tools or works of art. One is an opportunity to significantly improve an user’s life. The other will convey feelings: laughter, anger, joy, sadness. The possibilities are endless.

    Apps are opportunities to connect and to share. When I made my budgeting app PyroHabit in September, I was pretty disappointed to see that no one had any use for it. But later it inspired me to build Findependents. The kind of product you want to stand for. The kind of product that attracts passionate people to you. It all started with an useless app.

    I love tech. It is time to make.