Jekyll2021-09-27T01:51:13+00:00https://yndajas.co/feed.xmlYnda JasThey/them. Queer non-binary transfemme activist, socialist, creative, lapsed academic and developing coder.Ynda JasScaling the Flatiron summit with StackStore: running with React, Redux and Rails2021-09-22T00:00:00+00:002021-09-22T00:00:00+00:00https://yndajas.co/coding/2021/09/22/Scaling-the-Flatiron-summit-with-StackStore-running-with-React-Redux-and-Rails<p>Having paced through three projects on Sinatra, Rails and JavaScript earlier in the year, I took a little longer to work through the curriculum and get started on the final Flatiron project, which is focused on React and Redux. After initially
setting up the Rails API backend a few weeks ago, I took some time refamiliarise myself with the structure and flow of React/Redux apps by watching through the majority of a live build demo. I gradually started building out the structure of the
app, then - as usual - couldn't stop once I got into the flow of things.</p>
<p class="before-list">The task for the final project is to build a React/Redux app with a Rails API backend. I decided to create StackStore, a simple application for finding, keeping, tagging and making notes on Stack Overflow questions. With
StackStore, you can:</p>
<ul>
<li>search for Stack Overflow questions by title</li>
<li>view questions and answers</li>
<li>save questions to your own store</li>
<li>add tags and notes to questions and view questions by tag</li>
</ul>
<p>It seems like a fairly simple app when you list the features - and the entity relationship diagram below is indeed much simpler than my last few apps - but some of the best apps are narrow in scope. The entity relationship diagram below is for the
API backend; you can also open the diagram as <a href="/assets/resources/StackStore_erd.pdf" target="_blank">a PDF</a>.</p>
<div class="container d-flex justify-content-center">
<img src="/assets/images/StackStore_erd.png" alt="Entity relationship diagram">
</div>
<p>With this app, I was more interested in doing one or a few jobs well than doing lots of jobs. I wanted to make the most of React, Redux and various packages in order to develop a more streamlined and straightforward user experience
than in previous projects. The use of state, props and components in a React/Redux framework allows you to provide interactive features and responsive data (i.e. retrieval and manipulation) without requiring a bunch of reloads as with a traditional
model-view-controller app, or highly complex and custom code as with a vanilla JavaScript single page app.</p>
<p class="before-list">The full requirements for the project were as follows:</p>
<ul>
<li>use of ES6 syntax</li>
<li>use of <code>create-react-app</code></li>
<li>one HTML page to render the app - I ended up with two, one of which is a 404 used to run a redirect script (not my own) when GitHub Pages tries to load a route via a non-existent HTML file</li>
<li>at least five stateless components and three routes - I ended up with many stateless components and seven routes: home/login, about, saved questions, edit question, tags, saved questions by tag and search</li>
<li>RESTful routing using React Router</li>
<li>use of Redux middleware to control state - I used this except for managing the values of controlled forms before submission</li>
<li>async actions with fetch requests using Redux Thunk</li>
<li>Rails API with standard JavaScript <code>fetch</code> syntax (not jQuery)</li>
<li>display handled by front-end</li>
<li>styling</li>
</ul>
<p>Throughout my Flatiron journey, I tended to have an initial sense of challenge about the projects and their requirements, not least because they often require putting together a number of different elements that the taught curriculum has covered
in isolation. However, despite the challenge, I've always pushed myself to make a useable product and in the process learn new stuff as my idea would organically evolve during the development process. As a result, I end up feeling pretty confident
by
the end of each project, not only in want I've learnt through the curriculum, but in full-stack development and coding more broadly. Now it's time to advance the challenge one step further as I start looking for opportunities to pursue a
professional career in coding.</p>
<hr>
<p>Below is a demo of the app, which is hosted on Heroku and GitHub (Pages) and can be accessed via <a href="http://stackstore.yndajas.co" target="_blank">stackstore.yndajas.co</a> (you will be redirected to GitHub).</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/47qTNiLzgQU" width="100%" height="100%" frameborder="0"
style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasHaving paced through three projects on Sinatra, Rails and JavaScript earlier in the year, I took a little longer to work through the curriculum and get started on the final Flatiron project, which is focused on React and Redux. After initially setting up the Rails API backend a few weeks ago, I took some time refamiliarise myself with the structure and flow of React/Redux apps by watching through the majority of a live build demo. I gradually started building out the structure of the app, then - as usual - couldn't stop once I got into the flow of things.Serving comedy, cats and Chris Dave’s hi-hats with JavaScript on a bed of Rails2021-04-14T00:00:00+00:002021-04-14T00:00:00+00:00https://yndajas.co/coding/2021/04/14/serving-comedy-cats-and-Chris-Daves-hi-hats-with-JavaScript-on-a-bed-of-Rails<p class="before-list">In the penultimate independent project of the Flatiron curriculum, the task is to build a single page application with a HTML, CSS and JavaScript frontend and a Rails API backend. Further requirements include:</p>
<ul>
<li>interactions between the client (frontend) and server (API backend) handled using AJAX with JSON</li>
<li>object-oriented JavaScript</li>
<li>a resource with at least one has-many relationship</li>
<li>at least three AJAX calls using <code>fetch</code> covering at least two CRUD actions</li>
<li>RESTful API routes</li>
</ul>
<p class="before-list">Though not required, I tried to incorporate JavaScript into the last two projects where it made sense to do so, and previously wrote a Chrome extension as the final project for CS50. However, this was the first time I
used JavaScript:</p>
<ul>
<li>to control the vast majority of the frontend view rendering</li>
<li>to handle server communication</li>
<li>using object-oriented patterns</li>
</ul>
<h4>The app</h4>
<p>After browsing through <a href="https://github.com/public-apis/public-apis" title="Public APIs" target="_blank">a long list of public APIs</a> for inspiration, I decided to build an app that would bring together three separate resources: jazz
videos, cat images/GIFs and jokes. The app allows you to retrieve a random example of each of these resources and choose whether to save it to your collection.</p>
<p>For the cats and jokes, I decided to use a couple of APIs from the long list, while the jazz videos - a more familiar domain - would be self-curated with data persisted to the app's own API database.</p>
<p>Continuing in the spirit of previous projects, I wanted to make an app that would actually be useable, rather than <i>just</i> a tech demo (even if that's one of the main purposes). A key component of making a usable app in which users can save
and review collections of resources is - rather obviously - a user model. I decided to include this in the API and use client-server communication to handle user and session management. Initially I planned on using standard Rails session
management, but setting up sessions is complicated by the stripped-back Rails setup for APIs. In the end, I built a custom token-based authorisation system that would prevent access to user-specific API endpoints without a unique access token.
Attempting to access a user's data directly via the API's endpoints, e.g. at <a href="https://jazzcatcom.herokuapp.com/users/1/cats" title="Example user data endpoint" target="_blank">jazzcatcom.herokuapp.com/users/1/cats</a>, will render an error,
and any AJAX requests made to read or create user resources (essentially anything except the <a href="https://jazzcatcom.herokuapp.com/jazz-videos" title="Jazz videos index" target="_blank">index of all jazz videos</a>) will likewise fail without
the user's access token provided as a header.</p>
<p>The final entity relationship diagram for the API backend is below; you can also open the diagram as <a href="/assets/resources/JazzCatCom_erd.pdf" target="_blank">a PDF</a>.</p>
<div class="container d-flex justify-content-center">
<img src="/assets/images/JazzCatCom_erd.png" alt="Entity relationship diagram">
</div>
<p>On the frontend side, it took a while to build an understanding of how object-oriented JavaScript would fit within the app as a whole without simply duplicating the functionality of the backend. The Flatiron module on vanilla JavaScript covers the
syntax (both using ES6 syntactic sugar and the more traditional constructor function syntax), but it does so in a few pretty brief sections towards the end without much discussion of how it actually fits into a full-scale project. After reviewing a
number of other student's JavaScript project repositories, I identified a number of patterns that hadn't been covered in the curriculum, most notably separating out JavaScript files and classes into an overarching app file/class, one or more
adapters, and classes for each resource which - adhering to separation of concerns principles - would focus on rendering logic.</p>
<p>Initially I built adapters corresponding to each resource, but in the end - following the DRY principle - I abstracted the logic into a single adapter class. The app is not totally DRY, and the main JavaScript app class feels like it could adhere
to the separation of concerns principle better if I introduced additional helper classes, but throughout the build process I tried to identify areas in which abstraction could DRY both the frontend object-oriented JavaScript code and the backend
Rails code.</p>
<hr>
<p>Below is a demo of the app, which is hosted on Heroku and GitHub (Pages) and can be accessed via <a href="http://jazzcatcom.yndajas.co" target="_blank">jazzcatcom.yndajas.co</a> (you will be redirected to GitHub).</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/x-QS4K6tN78" width="100%" height="100%" frameborder="0"
style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasIn the penultimate independent project of the Flatiron curriculum, the task is to build a single page application with a HTML, CSS and JavaScript frontend and a Rails API backend. Further requirements include: interactions between the client (frontend) and server (API backend) handled using AJAX with JSON object-oriented JavaScript a resource with at least one has-many relationship at least three AJAX calls using fetch covering at least two CRUD actions RESTful API routesWorkinonit with Rails: riding high, building and passing pitfalls2021-03-14T00:00:00+00:002021-03-14T00:00:00+00:00https://yndajas.co/coding/2021/03/14/Workinonit-with-Rails-riding-high-building-and-passing-pitfalls<p>In the third major independent project of the Flatiron software engineering curriculum, students are tasked with building an app using the Ruby on Rails framework. The app should be some kind of content management system incorporating complex forms managing associated data with the help of RESTful routes.</p>
<p class="before-list">I decided to build a web app that allows users to manage their search for a job without having to deal with spreadsheet software, disorganised notes or uncoordinated chaos. With <a href="http://workinonit.yndajas.co" target="_blank">Workinonit</a> - the name an ode to extraordinary music producer J Dilla - users can:</p>
<ul>
<li>find jobs by keywords (e.g. job title) and location</li>
<li>add jobs by URL or manual entry</li>
<li>keep track of progress on job applications</li>
<li>save and review feedback from and notes on companies</li>
</ul>
<h4>Riding the Rails</h4>
<p>Moving to Rails for this project required learning a lot of new syntax and ways of working, but the more you immerse yourself in its "convention over configuration" approach, the more you can start to focus on only the customisation that actually matters to your project.</p>
<p class="before-list">Approaches that differed from the Sinatra framework included:</p>
<ul>
<li>separating out <strong>route definition</strong> from <strong>controller actions</strong>, and <strong>implicit rendering</strong>. This leads to cleaner-looking controllers, free from all the route specification and calls to render templates where they follow standard RESTful conventions</li>
<li><strong>helper methods</strong> and <strong>before actions</strong>. In the Sinatra app I'd made significant use of before hooks, but in Rails you can define private methods for use both within the controller and before any controller actions fire using the <code>before_action</code> specification. The <code>helper_method</code> declaration also allows you to be more explicit about which methods to make available to views</li>
<li>using <strong>Rails helpers</strong> in controllers but particularly views. The most useful of these are arguably things like <code>link_to</code> combined with path (or URL) helpers, allowing you to reference paths to particular routes by name rather than by typing the actual route out everywhere - much DRYer! In the end, I decided to go all out and write 99% of the views using Rails tag helpers. This might be overkill, but it does <em>feel</em> pretty nice, and leads to a more consistent syntax than would be the case with more of a mix of raw HTML and Rails helpers</li>
</ul>
<h4>Building on before</h4>
<p>The streamlining offered by Rails provided more space to build on and extend existing skills and knowledge. The project have me a chance to solidify my grasp on how to apply the <strong>model-view-controller</strong> paradigm within real domains. Within this project, I tried to think more carefully about the separation of concerns principle. Where in the last project I had a bit of an blurred distinction between the roles of my models, controllers and views, with some heavy custom SQL querying going on in the controller and in some cases some significant data manipulation in the views, this time I tried to keep that to a minimum. Models handled the majority of data-focused logic and controllers flow-based logic, with views handed more instance variables with data properly prepared, leaving a much smaller amount of logic focused on hiding/showing elements based on the data being passed from the controller. I'm still not 100% confident the balance is quite right - perhaps the concerns could be even more straightforwardly separated, but it feels like a significant step forward from the last project.</p>
<p>In the last project, all but one <strong>model</strong> either belonged to users, or belonged to a model that belonged to users. In this app, there's still no real user-to-user interaction, but I thought about how some data might not need to be unique for every user, which in a production environment may save database space by avoiding duplication of data, and allow for potential future expansion into user interaction experience. I made almost all pages require login with the exception of scraped webpages, meaning users could <strong>share</strong> a job they've found. Having jobs not belong to a user, and having one record per scraped job listing no matter how many times it's scraped, means that there will only ever be one URL tied to that job... unless some key details change, leading to unique records for a single job. This also offers the potential for tracking how many users have saved/are interested in a particular job, which could open up opportunity for further interesting informational features down the line. An entity relation diagram representing the app's models is below; you can also open the diagram as <a href="/assets/resources/Workinonit_erd.pdf" target="_blank">a PDF</a>.</p>
<div class="container d-flex justify-content-center">
<img src="/assets/images/Workinonit_erd.png" alt="Entity relationship diagram">
</div>
<p class="before-list">I also built on my knowledge of:</p>
<ul>
<li><strong>scraping</strong> - I decided to incorporate the primary focus of the first project as a feature of this one, only this time with shorter, more reusable methods with more specific jobs</li>
<li>CSS, this time using <strong>SCSS</strong> to streamline specification of styles using complex hierarchical selectors, as well as incorporate variables (making it much easier to manage a colour theme) and even a function</li>
<li><strong>JavaScript</strong>/JQuery, using scripts to:</li>
<ul>
<li>ask for confirmation before deleting data</li>
<li>play a J Dilla track (adapting the script I used on CS50 problem set project <a href="https://nihongooo.yndajas.co/" target="_blank">Nihongooo!</a>)</li>
<li>prepend "https://" in URL fields if not provided</li>
<li>require at least one checkbox in a form before submission</li>
<li>require at least one input - URL or textarea - to have data before form submission</li>
<li>tidy up the URL after OAuth authentication, getting rid of ugly suffixes like "#_=_" or just "#" from Facebook and Google</li>
<li>toggle a feedback field that should only be available for unsuccessful applications</li>
</ul>
<li>how often to <strong>commit</strong>. I was aware that in previous projects I'd committed too little, often providing long, multi-line commit messages describing a bunch of changes. This time, I tried to keep changes down to what I could usefully describe within one succinct commit message. I didn't always succeed, and sometimes the commits felt too small, but it feels like a step in the right direction</li>
</ul>
<h4>Production pitfalls, deployment dangers</h4>
<p>As per the last project, I decided to deploy the app to a production environment using Heroku. This brought with it a number of challenges that I had to overcome in order to get a working product.</p>
<p>The first was getting the <strong>PostgreSQL</strong> database set up. This took a while, but this time I managed to get it working fairly consistently in development, test and production environments - next time I might try using PostgreSQL from the start rather than switching at the point of deployment</p>
<p>The second challenge was getting Heroku to <strong>build</strong> the app successfully. Heroku errored out of the build process, saying there was a problem with precompiling assets. This was a bit of a red herring - I ended up reading a number of threads on issues with CSS/SCSS file extensions and other stuff related to the contents of the asset folder, when the actual issue was the approach I was taking to providing app IDs and secrets in the OmniAuth config. In the end I needed to switch from using credentials.yml.enc to environment variables in .env locally and config variables in Heroku.</p>
<p>Once the build passed, when trying to open the app I once again faced Heroku's <strong>H10</strong> errors, which provide very little detail about their cause. With very little information, it's hard to know where to look for solutions - H10 errors can be almost anything. In the end, I discovered a help page from Heroku which suggests specific code for your <strong>puma.rb</strong> file in the config folder, which differs to the default Rails code, as well as a different <strong>Procfile</strong> bootup command to the one they suggest on their main guide to getting started with Rails 5 on Heroku. Unclear or incomplete guidance that makes too many assumptions of the reader seems to be a recurring issue... but after making those changes, the app launched successfully!</p>
<p>With a working app, I decided to sort out <strong>OAuth</strong> to work in the live environment. This was surprisingly easy (after having dealt with the environment/config variables earlier)! It mostly involved telling each provider the new domain and callback details. With Google, getting it working with any Google account rather than pre-specified ones will require sorting out a privacy policy and submitting it for approval, but otherwise this step didn't cause much frustration!</p>
<p>The last issue, and a minorly app-breaking one, is that <strong>scraping</strong> can work quite differently - or not at all - when working outside of a local environment. In local testing, everything was (is) working great, but in the live environment, scraping produced a bunch of internal server errors. The main issue here was websites denying permission to scrape their pages. Not content leaving a negative experience for the hordes of users waiting to manage their job applications on Workinonit, I spent an extra few hours working through these issues, eventually adding in some error/exception handling within the scraper class. This logic rescues the app from crashing if it encounters errors when scraping content. I'd already implemented <code>before</code>-<code>rescue</code>-<code>end</code> exception handling for user-provided URLs, so this was mostly a case of taking that and extending it to deal with other scraping features. Having more but smaller scraping methods made it a bit easier to address these issues without rewriting existing logic. Unfortunately these HTTP errors mean that scraping works inconsistently for two of the three providers - sometimes they deny requests and sometimes they don't - and these are the only two that provide proper non-UK job coverage, but at least the internal server errors are fixed!</p>
<hr>
<p>Below is a demo of the app, which is hosted on Heroku and can be accessed via <a href="http://workinonit.yndajas.co" target="_blank">workinonit.yndajas.co</a> (you will be redirected to Heroku).</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/PYwX1QGj6os" width="100%" height="100%" frameborder="0" style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasIn the third major independent project of the Flatiron software engineering curriculum, students are tasked with building an app using the Ruby on Rails framework. The app should be some kind of content management system incorporating complex forms managing associated data with the help of RESTful routes.Gender beyond the binary: visualisation, language and conceptual frameworks2021-02-19T00:00:00+00:002021-02-19T00:00:00+00:00https://yndajas.co/articles/2021/02/19/gender-beyond-the-binary-visualisation-language-and-conceptual-frameworks<p><em>The first half of this article is <b>not</b> a critique of the people whose tweets or images I embed, nor the many, many more people whose words and images I could have referenced. Travis is awesome, I don't know Sascha but he seems awesome
from Twitter, and most of the people taking on the difficult task of explaining gender beyond the binary are awesome. My critique is squarely aimed at the tools we've been handed down, not the people who make the most of them!</em></p>
<hr>
<h4>Capturing gender: existing visual tools and conceptual understandings</h4>
<p>When I first started really actively thinking more introspectively about gender, I found that while many of the common visual methods and heuristic tools available to help people understand and situate their own gender were to an extent useful,
they were conceptually quite limited and limiting.</p>
<p>One approach is to use scales, the simplest version of which has female on one end, male on the other. People often say 'gender is a spectrum', and this is arguably the most classic and common way of representing this idea. Another version turns
the one-dimensional scale (or line) into a two-dimensional triangle, with female and male top left and right, agender at the bottom - essentially the same scale but with an extra axis for strength of alignment toward different genders (or to gender
as a whole).</p>
<p>The Gender Unicorn and others use separate scales for femaleness, maleness and 'other'-ness, which allows for capturing the multiplicity represented by bigender or multigender experiences. The Gender Unicorn puts these scales alongside scales for
'gender expression', sex assigned at birth and emotional and physical attraction - whether the implication is that these are (co-)constitutive of or simply adjacent to gender, I'm not sure.</p>
<h5>Relations and between-ness</h5>
<p>While I recognise the value of these tools - their simplicity arguably a contributing factor - one of the biggest issues I have with them is how they at best uncritically reflect and at worst influence the most basic mainstream understandings of
gender (as a spectrum).</p>
<p>Scales with female and male on either end, the triangle that adds an axis for capturing agender experiences but retains the polarity of femaleness and maleness, and announcements like "ladies, gentlemen and everyone in between" all represent the
same limited understanding of the diversity of non-binary experiences.</p>
<div class="container d-flex justify-content-center">
<figure class="figure">
<img src="/assets/images/gender_spectrum.jpg" class="figure-img img-fluid rounded" alt="A classic gender 'spectrum' scale">
<figcaption class="figure-caption text-center">Lines: a classic gender 'spectrum' scale<sup><a href="#note1">1</a></sup></figcaption>
</figure>
</div>
<p>What does it mean to be 'between'? Well, green is between blue and yellow (in the 'visible spectrum' and theories of colour, though interestingly not in the image above!). You can think of it as not quite either, or a little of both. Mainland USA
is between Mexico and Canada - it's not quite as south as Mexico but not quite as north as Canada. 1 is between 0 and 2 - more than 0 and less than 2. What do all these have in common? They can be described in terms of their relation to their
neighbours - they're the middle ground<sup><a href="#note2">2</a></sup>. You can also think of between-ness as an average - add the numbers, the latitude of the countries or the RGB values of the colours together, divide by two and you'll get the
midpoint.</p>
<p>The problem that arises here is not so much in thinking about things relationally, but in the relations that the existing gender visualisation tools allow to exist, or more importantly the gender(ed) experiences they preclude.</p>
<p>For some people, their non-binary identity is indeed a little female, a little male, or 50/50, or the average of 'the' two options. The middle of the scale <em>could</em> represent bigender people, perhaps even agender people if you take it as not
an average but a neutral space. If the middle were bigender, the left might equal 1 and the right 2, with the middle equal to 1.5. If the middle represented agender, perhaps it would equal 0 while the end points would be -1 and 1. But how do you
distinguish the two - bigender and agender, and perhaps other interpretations - using the scale alone?</p>
<div class="container d-flex justify-content-center">
<figure class="figure">
<img src="/assets/images/gender_triangle_female_male_agender.jpg" class="figure-img img-fluid rounded" alt="The Gender Spectrum Scale">
<figcaption class="figure-caption text-center">Triangles: <a href="https://www.deviantart.com/chrystall-bawll/art/The-Gender-Spectrum-Scale-566049414" target="_blank">The Gender Spectrum Scale</a></figcaption>
</figure>
</div>
<p>For many, being non-binary is not occupying a middle ground at all so much as another ground altogether - if female and male were Canada and Mexico or vice versa, non-binary might be Botswana, Belarus or Burkina Faso. It might not be that far away
from female and male - Bolivia, for instance. For yet others, their non-binary identity may be constituted by dual citizenship. They may or may not view that dual citizenship as half one thing, half the other - they may view it as fully both, or an
imbalanced mixture of the two that doesn't necessarily add up to 100%.</p>
<p>An alternative gender triangle exists in which agender is replaced by non-binary, but again I find this fairly limiting - it assumes a regularity both in terms of how different genders work and in terms of the space between them. Without its
labels, the triangle looks the same every 120 degrees it's rotated (it has a 'rotational symmetry of order three') with each gender the same distance away from every other gender. This is limiting not only to the extent that it assumes female, male
and non-binary are three equally spaced out entities with everything else - again - in between, but also in that it takes non-binary (and female and male) to be a singular point in a three-point representation of gender. Recognising non-binary
experiences is not about shifting from a binary system of gender to a ternary one - it's about moving to a much more boundless, limitless and thereby liberating understanding of the diversity of gender and gendered life. Sure, you <em>could</em>
occupy the space in the middle of the triangle, but everything is confined within or between the space created by three equal extremes. An equilateral triangle goes beyond a one-dimensional scale of female to male, but for me it just doesn't go far
enough in capturing and enabling the true variety of lived experiences and understandings of gender that exist within different people.</p>
<p>Another similar two-dimensional visual method of representing gender is a square or a plot with axes for femaleness and maleness, ranging from no alignment to full alignment. In this representation, female is 100% female and 0% male, male is the
opposite, agender is 0% female and male and non-binary and other 'other' categories are 100% female and male, or - again - everything in between, everything in the middle ground. To me this makes little sense beyond representing bigender
female/male people, and suffers from the same issues of relational prescriptiveness as the one-dimensional scale and two-dimensional triangles. Non-binary people - for the most part - are not defined by dimensions of femaleness or maleness.</p>
<div class="container d-flex justify-content-center">
<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">there are a lot more identities than the ones I’ve just named! here is a simplified visualisation of the gender spectrum that I made. remember that this isn’t perfect and it’s not possible to accurately visualise this, but
I hope it helps anyway. <a href="https://t.co/SMKwYiSugD">pic.twitter.com/SMKwYiSugD</a></p>— Sascha Viktor 📌 (@confusedophan) <a href="https://twitter.com/confusedophan/status/1150364839967100928?ref_src=twsrc%5Etfw">July 14, 2019</a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
<h5>Transcendence and beyond-ness: what are we talking about again?</h5>
<p>Another common way of describing non-binary people is as those who have transcended gender. While this sounds great and uplifting and may rouse audiences at queer cabaret nights, have we really?</p>
<div class="container d-flex justify-content-center">
<blockquote class="twitter-tweet">
<p lang="en" dir="ltr">Petition to get David Hoyle to do his iconic line “ladies and gentlemen and those lucky enough to transcend gender” at all theatre announcements now. Then *everyone* is included.</p>— Travis (@travisalabanza) <a
href="https://twitter.com/travisalabanza/status/1191687472541044736?ref_src=twsrc%5Etfw">November 5, 2019</a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
<p>Transcendence is essentially going beyond something - transcending gender is going beyond gender. Now, the idea of a world without gender - or gender categorisation at least - in which everything that we think of as gendered or gender-related is
not associated with specific groups but instead fluid and accessible to all may quite reasonably sound utopian for many people. But that's not really the discussion we're having here. In our current cultural and historical situations, gender (or
gender categorisation) is <em>very</em> real - it affects the opportunities and experiences available to us, including those for which we may have no agency to accept or reject.</p>
<p>Further, transcending something means you are no longer that thing, or no longer have that thing - you are <em>beyond</em> it. If we transcend gender, the implication is therefore that we no longer have a gender, or we are somehow outside of
gender. This might make sense if you're agender or reject gender categories on political grounds, but an immediate implication of this way of thinking is that female and male are genders, non-binary is not - not a gender, not real, not valid.</p>
<p>Obviously when the idea of 'transcendence' comes from within the community, this invalidation is not intentionally implied - it's most definitely not meant to harm - but impact is often more important than intention. The impact may be that those
whose experiences haven't (yet) led to them to non-binary identification, and arguably those who are in the embryonic stages of understanding their own gender, infer that non-binary is - and <em>only</em> is - beyond-ness, transcendence,
<em>not</em> gender. If that doesn't resonate with them - if they don't feel quite transcendent, for whatever reason - then what are they left with?</p>
<p>A similar phrase replaces "those who have transcended gender" with "those who are too fabulous to decide". Again, this may sound great when you first hear it in a cabaret bar - and yes, non-binary people are of course fabulous - but the
implication is us non-binary people are simply indecisive and struggling to pick between the two options. Nope.</p>
<h5>Siloed genders: <em>what</em> are we talking about again?</h5>
<div class="container d-flex justify-content-center">
<figure class="figure">
<img src="/assets/images/genderunicorn.jpg" class="figure-img img-fluid rounded" alt="The Gender Unicorn">
<figcaption class="figure-caption text-center">Many lines: <a href="https://transstudent.org/gender" target="_blank">The Gender Unicorn</a></figcaption>
</figure>
</div>
<p>The alternative to having female and male on opposite ends of a scale proposed by tools like The Gender Unicorn is to separate them out into completely independent scales, with non-binary/other genders forming a third scale. At first, this seems
great - it removes the polarity and avoids treating non-binary experiences as some kind of middle ground between two extremes. It allows for a variety of bigender identification by aligning with more than one gender. It allows for agender
identification by aligning with no gender. It allows for demigender identification by allowing for differing degrees of identification with (multiple) genders. That's three ticks!</p>
<p>What is misses, however, is any kind of representation of what those genders actually mean. It sanitises gender to the extent that it's just a collection of unrelated scales, and the scales look - from the outside - the same for everyone. The same
in that they say nothing at all beyond what the category is and how much an individual feels aligned to it. They say nothing of how similar or different categories are from each other, let alone why. In order to understand this, it's vital to first
understand what actually constitutes particular genders and by extension where to draw the line between one category and another. Separate scales don't say whether there even are any fixed lines - perhaps there are contested borders, unclaimed
territories and international waters?</p>
<p>This naturally leads to the question of - if we want our genders to look a little more Texas BBQ and paprika than all 'original' - what <em>should</em> they look like? Well, in reality they look different to different people. To some people,
female and/or male may indeed be 'original', and perhaps that's what leads them to feel aligned or unaligned with those categories. To others, female may look like cheddar cheese and male may look like smoky bacon, with non-binary more closely
resembling salt and vinegar.</p>
<div class="container d-flex justify-content-center">
<figure class="figure">
<img src="/assets/images/Pringles.jpg" class="figure-img img-fluid rounded" alt="Pringles">
<figcaption class="figure-caption text-center">Pringles flavours from <a href="https://www.delish.com/food-news/g25748262/best-pringle-flavors" target="_blank"
title="We Tasted Every Single Pringles Flavor That Exists—And Here's Our Official Ranking">Delish</a>. Not sponsored; also vegan!</figcaption>
</figure>
</div>
<p>This variation in how people view genders is not just okay, it's natural. Our cultural, historical and personal backgrounds all factor into how we understand and view different gender categories. Two people may share very many characteristics -
personality, behaviours, aesthetics and so on - but identify in two different ways (so what <em>is</em> sexuality!?<sup><a href="#note3">3</a></sup>). A common example - and sometimes a source of transphobia<sup><a href="#note4">4</a></sup> - is
butch cis lesbians and (butch) trans men. Thinking more transculturally, 'non-binary' might not mean much to some cultures outside the 'Anglosphere', or to people who lived before the 20<sup>th</sup> century, but that doesn't mean that some of the
experiences and feelings aren't the same or very similar despite differences in categorisation (or lack thereof)<sup><a href="#note5">5</a></sup>.</p>
<p>Ultimately we all conceptualise gender in unique ways, so how do we then deal with visualising something that's so individual (before even thinking about our own positionality)?</p>
<h4>Mapping gender: an inherently imperfect pursuit</h4>
<p class="before-list">So the issues that need addressing in building better gender visualisation tools include:</p>
<ul>
<li>not polarising femaleness and maleness with non-binary occupying the middle ground</li>
<li>treating non-binary experiences as real, valid gender experiences, not experiences that necessarily transcend gender entirely</li>
<li>representing relationality - how similar or different/close or far are different genders?</li>
<li>allowing for individual variation in our understandings of gender categories</li>
</ul>
<p>I've been intending to write this article for at least four years, maybe more. Back then, I had the idea that maybe we could represent gender not as points on singular or multiple one-to-two-dimensional lines, triangles or squares, but rather as
some kind of space with irregular shapes and varying relationships between the shapes. The structure of this space should not be predetermined, but rather informed by an individual's own understanding of different gender categories and their
relationship to them.</p>
<p>It's these principles that brought me to thinking about maps. Maps are not only <em>cool</em> and <em>interesting</em>, but also allow for all of the above and more.</p>
<h5>Mapping as a visual representation of gender</h5>
<p>Below is an example map I created <em>a long time ago</em>. In it, we see representations - via the green shapes - of eight different genders. They vary in size, shape and space between each other. Most are islands in this map, while two overlap -
perhaps a contested border, or perhaps there are no borders? I'll discuss what might inform the landscape of the map shortly, but first I'll explain what the people on the map may represent.</p>
<div class="container d-flex justify-content-center">
<figure class="figure">
<img src="/assets/images/gendermap_example.png" class="figure-img img-fluid rounded" alt="Example gender map">
<figcaption class="figure-caption text-center">Example gender map</figcaption>
</figure>
</div>
<p>On the map are six people icons or avatars of four different colours, one colour (and number) representing one person. Person one may be genderfluid: they occupy two positions - one near female and one near male - and, as indicated by the arrows,
they move between these spaces. Person two may be genderqueer or demi-genderqueer - they're closest to the genderqueer island or shape, but at the moment they're just a little off the coast. Person three is on island or hypothetical gender 'L' -
compared with person two, their alignment with a particular gender is stronger, so they probably wouldn't refer to themself as 'demi'. Like person one, person four also occupies two positions, however they don't move between these positions -
they're most likely bigender with a strong alignment with hypothetical gender 'R' and a secondary (but fairly strong) alignment with hypothetical gender 'C'.</p>
<p>This example doesn't show how each of these people's maps are likely to have a different landscape, but it does show how differing gender categories and our relationships with and experiences of them can be represented. You could also add an icon
representing gender/sex assigned at birth, and the similarity or difference between that and your current positionality or understanding of your own gender may inform how much the category 'trans' feels like an accurate description (versus 'cis').
</p>
<h5>The underlying system of gender</h5>
<p>Below is an attempt at capturing all of this in a system or model of gender.</p>
<div class="container d-flex justify-content-center">
<figure class="figure">
<img src="/assets/images/gendersystem.png" class="figure-img img-fluid rounded" alt="Gender system">
<figcaption class="figure-caption text-center">Gender system</figcaption>
</figure>
</div>
<p>I provided a short description of this and how it relates to mapping in my article '<a href="https://www.budrich-journals.de/index.php/insep/article/view/35952" target="_blank">Sexuality in a non-binary world: redefining and expanding the
linguistic repertoire</a>'.</p>
<p>In essence, <b>shapes</b> are the categories we use to describe our gender, as represented by the shapes on the map (or mostly islands in the example above). Shapes might include female, male, non-binary, neutrois, genderqueer and so on.</p>
<p class="before-list"><b>Dimensions</b> are what constitute those shapes - they inform our understanding of what it means for us to be particular gender categories. Dimensions, depending on your cultural and historical background, might include:</p>
<ul>
<li>femininity and masculinity</li>
<li>expression (or presentation, 'embodiment' or 'semiotic enactment')</li>
<li>behaviour</li>
<li>social roles and positioning (power)</li>
<li>romantic and sexual orientation (in some cultures)</li>
</ul>
<a class="embedly-card" href="https://www.reddit.com/r/traaaaaaannnnnnnnnns/comments/9asiej/gender_isnt_a_spectrum_its_a_triangular_zone_of/e4ykv5x">Card</a>
<script async src="//embed.redditmedia.com/widgets/platform.js" charset="UTF-8"></script>
<p>The not so serious Reddit comment above is a response to someone sharing a version of the gender triangle (in an equally not so serious post!). I like the idea of "10 planes of reality". This is similar to my idea of the dimensions of particular
gender categories, or in other words the attributes that come together to constitute the whole. The dimensions that are important and how important they are will vary from culture to culture, person to person, but it's important to recognise these
in order to understand the landscape of our individual gender maps. Dimensions are what determine the shape of specific categories, and therefore the relations between them - or how similar or different/close or far they are to each other.</p>
<p>There may also be <b>subdimensions</b> below these dimensions. What do femininity, masculinity and particular queer or non-queer sexualities<sup><a href="#note3">3</a></sup> mean to you? What informs how you conceptualise and relate to them?
Subdimensions are the dimensions beneath the dimensions of shapes/gender categories. There may be yet further layers beneath the subdimensions - gender and other sociocultural phenomena are complex!</p>
<p class="before-list">Your positioning on the map, the shapes, your assigned gender/sex and the relationship between them are what constitute <b>metadata</b>. As I stated in the article cited above, "if you have two positions on the map, you might
categorise yourself as bigender, or if you are close to male perhaps demiguy, or if you shift between two positions then genderfluid". These kinds of categories are not shapes in and of themselves, but rather they provide us with a more detailed
picture of our relationships with different shapes. The kinds of metadata the map might cover include:</p>
<ul>
<li>number, e.g. bigender</li>
<li>fluidity/stasis, e.g. genderfluid</li>
<li>proximity/strength of alignment, e.g. agender or demigender</li>
<li>trans/cis</li>
</ul>
<p>Number and fluidity/stasis arguably both fall under representation of multiple alignment, however the former may be synchronous or simultaneous (two or more categories at once - bigender), while the latter may be asynchronous (moving between
categories - genderfluid).</p>
<h5>Imperfections and uplifting closing thoughts</h5>
<p>Simple maps are still ultimately two dimensional - even globes are <em>only</em> three dimensional. If we take only the high-level dimensions mentioned above - which might actually need breaking down further in order to be particularly meaningful
- we're already at seven dimensions: femininity, masculinity, expression, behaviour, social roles and positioning (power), romantic orientation and sexual orientation. One way of representing more gender dimensions is combining spatial dimensions
with other visual characteristics: curviness of borders, size/area, colour(s), patterns (dotted/striped/plain) and so on.</p>
<p>Another issue is that it takes time, and potentially some level of artistic ability or support in order to flesh out. Further, a static image can only go so far in representing fluidity within the categories themselves - what if our understandings
of particular gender categories shift over time or are like icebergs floating around as they break off from each other or changing by season? Travis Alabanza in '<a
href="https://metro.co.uk/2018/06/26/as-a-queer-gender-nonconforming-trans-person-dressing-for-the-heat-can-be-dangerous-7661419" target="_blank">When your body doesn’t meet society’s expectations, dressing for the heat can be dangerous</a>'
wrote about how "[a]s a queer, gender nonconforming trans person the heat brings challenges as often clothing (or the lack of it) increases the danger and proximity to abuse on the street"<sup><a href="#note6">6</a></sup>. Could these concerns
affect our relationships with gender categories between seasons, even between days and weeks?</p>
<p>The truth is gender is far too complex to fully represent using any visual method (and all maps are varying degrees of a lie<sup><a href="#note7">7</a></sup> - inherently imperfect), but regardless of the constraints we can make attempts to
develop visual methods that provide greater potential for more accurate representations of the diversity of gender. Even if it may be difficult and time-consuming to create a highly accurate map of your own, thinking about and mentally visualising
what your map might look like - as well as what dimensions and subdimensions may inform the shapes of the map - may prove to be a productive and insightful process in and of itself.</p>
<hr>
<h4>Notes</h4>
<p id="note1"><sup>1</sup> I believe the source is Mermaids and it looks like they got hate from transphobes for this. While I don't love this representation of gender, Mermaids are great, so <a href="https://mermaidsuk.org.uk/donate" target="_blank"
title="Donate to Mermaids">donate if you can</a> to counter the vitriol</p>
<p id="note2"><sup>2</sup> At least in terms of the dimensions of the scale in discussion - it would be a massive oversimplification to call the USA a cultural middle ground between Mexico and Canada!</p>
<p id="note3"><sup>3</sup> I discuss these questions and more in my article '<a href="https://www.budrich-journals.de/index.php/insep/article/view/35952" target="_blank">Sexuality in a non-binary world: redefining and expanding the linguistic
repertoire</a>'</p>
<p id="note4"><sup>4</sup> Jay Hulme discusses this in '<a href="https://jayhulme.com/blog/transmen" target="_blank">Transphobes and Trans Men</a>'</p>
<p id="note5"><sup>5</sup> My friend Dr Kit Heyam (who prompted me to finally write this article after years of shelving it!) discusses the historical dimensions of categorisation with regard to trans experiences and gender nonconformity in '<a
href="https://www.tandfonline.com/doi/full/10.1080/23337486.2019.1651045" target="_blank">Gender nonconformity and military internment: curating the Knockaloe slides</a>' and '<a
href="https://www.tandfonline.com/doi/full/10.1080/13500775.2020.1779465" target="_blank">Gendering Objects at the V&A and Vasa Museums</a>'</p>
<p id="note6"><sup>6</sup> I wrote about this and other concerns in 'From skinnies to skirts and crop-top shirts: traversing transfemme troubles', a chapter in '<a href="https://books.google.co.uk/books/about/Non_Binary_Lives.html?id=oGPGywEACAAJ"
target="_blank">Non-Binary Lives: An Anthology of Intersecting Identities</a>'</p>
<p id="note7"><sup>7</sup> See '<a href="https://books.google.co.uk/books/about/How_to_Lie_with_Maps.html?id=7pHeBQAAQBAJ" target="_blank">How to Lie with Maps</a>'!</p>
<hr>
<p>This is my gender, in case you wanted to know:</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/hDa9_LJoSTY" width="100%" height="100%" frameborder="0"
style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasThe first half of this article is not a critique of the people whose tweets or images I embed, nor the many, many more people whose words and images I could have referenced. Travis is awesome, I don't know Sascha but he seems awesome from Twitter, and most of the people taking on the difficult task of explaining gender beyond the binary are awesome. My critique is squarely aimed at the tools we've been handed down, not the people who make the most of them!Sinatra and the Racqueteer: crafting my first model-view-controller web app2021-02-01T00:00:00+00:002021-02-01T00:00:00+00:00https://yndajas.co/coding/2021/02/01/Sinatra-and-the-Racqueteer-crafting-my-first-model-view-controller-web-app<p class="before-list">The second major independent project of the Flatiron software engineering bootcamp requires that you build a Sinatra-based model-view-controller web app with ActiveRecord integration. Initial ideas included:</p>
<ul>
<li>a shopping wishlist management tool, with the ability to record items, priority, and prices and links at different stores</li>
<li>a DJ playlister, which could build on previous music library Flatiron labs by introducing users, playlists and links to the songs, artists and genres models</li>
</ul>
<p class="before-list">In the end, however, I decided to build an app that would allow you to keep track of your racquet sports activities by:</p>
<ul>
<li>recording and reviewing your matches, coaching and racquets</li>
<li>accessing breakdowns of each by sport, opponent, coach and more</li>
</ul>
<h4>Models, migrations and modules</h4>
<p>The only problem with this domain idea was that it's one I'm pretty familiar with, which led to building a fairly large and complex object-relational map - relative to what I've worked on so far - as can be seen in the entity relationship diagram below. Two PDF versions are available for a clearer view: <a href="/assets/resources/Racqueteer_erd_landscape.pdf" target="_blank">landscape</a> | <a href="/assets/resources/Racqueteer_erd_portrait.pdf" target="_blank">portrait</a>.</p>
<div class="container d-flex justify-content-center">
<img src="/assets/images/Racqueteer_erd_portrait.png" alt="Entity relationship diagram">
</div>
<p class="before-list">Almost all 15 models (or objects, or entities) have different relationships, which required some careful modelling of relationships and construction of migrations. Relationships in Racqueteer include:</p>
<ul>
<li><em>belongs to/has many:</em> everything except low-level join tables and results (as a closed class) belong to a user, enabling the user to edit all of their data without affecting other users' data. As well as belonging to users, locations, opponents, sports, and results have many matches and/or coaching sessions, and racquets in the case of sports</li>
<li><em>many-to-many/has many through:</em> coaches and coaching sessions, and racquets and matches have many-to-many relationships, and therefore join tables exist to map their relationship (leading to has many through relationships)</li>
<li><em>join tables:</em> racquets are essentially join tables for sports, frame brands/models and string brands/models (containing only an ID and foreign keys), but they have a belongs to/has many relationship with each of these entities differing from the many-to-many relationship with matches</li>
</ul>
<p>I created a couple of modules to support the models that contain name attributes. The first added functionality covered in Flatiron labs: generating slugs by name and finding instances by slug. The second module required, included and extended the first and established a belongs to relationship with users, avoiding repeating these elements of code in models with shared behaviour/relationships. The latter took a while to figure out, but I eventually discovered the concept of 'base' in modules, and used the method <code>self.included(base)</code> and within that methods <code>base.send</code>, <code>base.extend</code>, <code>base.include</code> and <code>base.belongs_to</code> to do the rest.</p>
<h4>Controllers</h4>
<p>Sitting between the complex models and complex views (more on that later), the controllers had to do some heavy lifting. The varying relationships between different models had implications on controller logic, one prime example being methods that invoked SQL queries in order to feed lists of objects, either on index or show pages or in providing options for inputs based on existing data. I used SQL methods - mostly in helper blocks - in order to sort and filter the data in a sensible way, which would've been harder to achieve using more standard Ruby and ActiveRecord methods. A number of these methods could feed data to views from multiple controllers, however some controllers needed unique sorting or filtering and therefore custom code. Figuring out the similarities and differences between the needs of different controllers and views was an ongoing process throughout development, requiring refactoring of code both to select additional columns in SQL queries and to move the methods between controllers.</p>
<p class="before-list">In addition to helper methods, I also made use of <code>before</code> hooks to preprocess requests, including:</p>
<ul>
<li>removing any trailing slashes from request paths unless the request is for the root ('/')</li>
<li>making all request paths lower case</li>
<li>redirecting to the homepage when logged out unless the request path is '/', '/login' or '/register', or '/users' with a method of 'POST'</li>
<li>removing leading/traling whitespace in params - though this is only a secondary safeguard, since this should be dealt with via JavaScript (more later)</li>
</ul>
<p>Another area of complexity within the controllers was destroying associated data. The app allows users to directly request instances of each model except the low-level join tables and results to be destroyed. However, since I chose to require almost all fields for every model, this meant destroying associated data. In the case of racquets, it's not enough to simply destroy a racquet's matches and match racquets, since that would leave behind any match racquets belonging to other racquets but the same match. In order to account for these, I iterated over a racquet's matches (using the ActiveRecord methods added by the has many through relationship), destroying all of each match's match racquets and then the match, before destroying the racquet. Effectively I went through the join table, then looked back at it from the other side. The same applied to coaches and coaching sessions.</p>
<h4>Views</h4>
<p>With the views, I tried to step things up from what I'd done before, integrating embedded Ruby (ERB) logic, dynamic forms, CSS and JavaScript to create a sense of polish in the user interface (and user experience). Since this post is already pretty long and there are lots of things I could cover here, I'll stick to listing some of the key technologies and features.</p>
<h5>HTML and ERB</h5>
<ul>
<li>conditional logic to include or exclude elements based on data fed from the controller</li>
<li>layout file with:
<ul>
<li>external styles (Bootstrap) and scripts (jQuery, Bootsrap)</li>
<li>custom styles and scripts, with two scripts loaded near the end of the document in order to operate on elements already loaded into the document object model</li>
<li>favicon inclusion including device-specific specification</li>
<li>multiple yield blocks (using 'sinatra/content_for' from the sinatra-contrib gem)</li>
</ul>
</li>
<li>adding links on show/index pages to the respective show pages of every piece of modelled data mentioned on the page, except those in headings</li>
<li>a range of HTML input types, with options provided based on existing associated data</li>
</ul>
<h5>CSS</h5>
<ul>
<li>Bootstrap, including use of different classes for positioning, navbar elements and other styling of specific elements</li>
<li>custom bullets, using tennis emoji!</li>
<li>softer-looking inputs, with a lighter, thicker border, rounded edges and more padding</li>
<li>background images</li>
</ul>
<h5>JavaScript</h5>
<ul>
<li>validating inputs for all four (or none of the four) of frame brand/model and string brand/model have been completed for new racquets</li>
<li>validating that at least one existing or new racquet for each match and coach for each coaching session is provided, while not requiring that both are provided</li>
<li>cloning inputs to add extra new racquets and coaches (while retaining unique IDs to retain label functionality)</li>
<li>toggling the background between a colour image, a monochrome image and plain white</li>
<li>warning and confirming before destroying data with a popup</li>
<li>removing leading/trailing whitespace in inputs on blur (when exited)</li>
</ul>
<h4>Deployment</h4>
<p>Lastly, I decided to try deploying the app via Heroku. Beyond trying to find clear documentation on how to do this (and particularly how to do it with Sinatra versus Rails), I encountered a couple of hurdles in achieving this.</p>
<p>First, SQLite is not accepted. SQLite contrasts with many alternative SQL implementations in that it stores the database within the app's own directory, rather than on a dedicated database server. Heroku does not accept this in production environments - i.e. for publishing on their platform - and recommends PostgreSQL. I had no idea how to do this, and found the documentation equally mystifying at first. Eventually I figured out how to get this set up locally through my Windows Subsystem for Linux setup and could test the app. Interestingly, when serving the app locally while using PostgreSQL, some SQL query typos broke the app in a way that was not the case with SQLite.</p>
<p>Once PostgreSQL was sorted, I tried deploying the app again, and it made it through the deployment process! However, when I opened the app on Heroku, it returned a generic error code meaning <em>something</em> is wrong. Something. Yay! After a bunch more research, I realised I was missing the essential 'Procfile', which tells Heroku what command to run to start up your app. The only problem was I didn't know what to put in that file... Eventually I thought of looking at the GitHub repository of another Flatiron Sinatra project I'd seen deployed on Heroku (Aurangzaib Danial's <a href="https://catchup-rss.herokuapp.com" target="_blank">Catchup!</a> RSS reader), and copying that was a success!</p>
<hr>
<p>Below is a demo of the app, which is hosted on Heroku and can be accessed via <a href="http://racqueteer.yndajas.co" target="_blank">racqueteer.yndajas.co</a> (you will be redirected to Heroku).</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/nK35Tuxfkso" width="100%" height="100%" frameborder="0" style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasThe second major independent project of the Flatiron software engineering bootcamp requires that you build a Sinatra-based model-view-controller web app with ActiveRecord integration. Initial ideas included: a shopping wishlist management tool, with the ability to record items, priority, and prices and links at different stores a DJ playlister, which could build on previous music library Flatiron labs by introducing users, playlists and links to the songs, artists and genres modelsExploring the wider world of coding in the winter of (COVID-19/)20/212021-01-31T00:00:00+00:002021-01-31T00:00:00+00:00https://yndajas.co/coding/2021/01/31/exploring-the-wider-world-of-coding-in-the-winter-of-COVID-19-20-21<p class="before-list">It's been a few months since my last major <a href="https://yndajas.co/coding/2020/10/05/platinuming-the-PSNProfiles-player-scraper-challenging-complexity-and-swelling-scope" title="Platinuming the PSNProfiles player scraper: challenging complexity and swelling scope">Flatiron bootcamp project</a>. Since then, via Flatiron I've learned about:</p>
<ul>
<li>object-relational mapping in Ruby with ActiveRecord</li>
<li>Rack and the mechanics of the web including HTTP requests and routing</li>
<li>the model-view-controller paradigm and its implementation in Sinatra</li>
</ul>
<p>I've also built on my previously primarily self-taught HTML and CSS skills - CSS now feels a little (little) bit less of a dark art - and completed Harvard's CS50 Introduction to Computer Science. This post is mostly focused on the final few projects of CS50, while the next will cover my second major Flatiron project.</p>
<p>For the final problem set of CS50, I decided to take the web track. This was partly because I wanted to get CS50 finished in 2020 and was conscious that I'd probably be more familiar with and efficient at completing web projects, but also partly because the technologies involved brought with them a level of unfamiliarity.</p>
<p>For the first of the two 'problems', I created a four-page website on learning Japanese called <a href="https://nihongooo.yndajas.co" target="_blank" title="Nihongooo!">Nihongooo!</a> The website incorporates the Bootstrap framework and JavaScript that injects and automatically plays a YouTube video of Japanese jazz when an "I'm feeling jazzy" button is clicked.</p>
<p>The second of the two problems involved implementing the Python and SQL (and HTML and CSS) introduced in the previous two 'weeks', as well as connecting to an API for up-to-date data retrieval in order to build out a simple web app with user management. This offered an opportunity to apply some of the HTTP requests and routing principles I'd been learning through Flatiron, but under Python's Flask web framework - a great chance to get used to Ruby's biggest rival!</p>
<p>After the last of the problem sets, the only thing left for CS50 was the final project. I'd enjoyed implementing a readability estimator in C in the third week of CS50 (known as 'week 2', because computer science) and reimplementing this in Python in week 6 (the seventh week), so I decided again to walk the line between the familiar and unfamiliar by building on this logic and reimplementing it once more, only this time within the framework of a JavaScript-based Chrome extension. This was a great chance to really dive into JavaScript in order to start getting experience of building more interactive, dynamic web experiences. Excitingly, the extension became my first project deployed beyond GitHub - it's now published on the Chrome Web Store as <a href="https://chrome.google.com/webstore/detail/selected-text-readability/gmmgeofdbimelpnapecnbdckopibaecl" target="_blank" title="Selected Text Readability">Selected Text Readability</a>. A demo is at the bottom of this page.</p>
<p>This winter I also started one of CS50's follow-on courses, CS50G or GD50 Introduction to Game Development. While I haven't had too much time to progress with CS50G, together it, CS50 and watching Celeste developer Noel Berry stream game development on Twitch (<a href="https://www.twitch.tv/noelfb" target="_blank" title="NoelFB on Twitch">NoelFB</a>) have really started to flesh out the foundations of my understanding of the wider world of coding!</p>
<p>In my next post, I'll talk about the Sinatra web app I've just developed (and deployed) for my second independent, self-led Flatiron project.</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/_AP_qb5wuMA" width="100%" height="100%" frameborder="0" style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasIt's been a few months since my last major Flatiron bootcamp project. Since then, via Flatiron I've learned about: object-relational mapping in Ruby with ActiveRecord Rack and the mechanics of the web including HTTP requests and routing the model-view-controller paradigm and its implementation in SinatraPlatinuming the PSNProfiles player scraper: challenging complexity and swelling scope2020-10-05T00:00:00+00:002020-10-05T00:00:00+00:00https://yndajas.co/coding/2020/10/05/platinuming-the-PSNProfiles-player-scraper-challenging-complexity-and-swelling-scope<p>Soon after completing my implementation of <a href="http://yndajas.co/coding/2020/10/04/coming-to-coding-chasing-the-challenge-and-tic-tac-toe-with-AI" title="Coming to coding, chasing the challenge and tic-tac-toe with AI">tic-tac-toe with AI</a> for a Flatiron lab, it was time to start working on my first major independent project. In the last couple months, a lot of my time has been taken up with moving and settling in to a new flat. Before the move I was only a few lessons and labs away from the project, and I think the feeling that I might have forgotten how to work with Ruby combined with not really having a sense of the required scale of the project led me to <strike>start procrastinating</strike> put my return to the bootcamp off a little bit longer than I really needed.</p>
<p>Well, coming off the back of a somewhat straightforward scraping lab, reading the requirements for the project led me to wonder what the big deal was. What, I just need to scrape some data and let a user choose what they want to see? That should only take a few hours! What I didn't account for was that when an idea for an app that would touch on my own interests came into my head, my own interests - as well as an inquisitive inclination and a wealth of data - would lead me to expand the scope of the project again and again and again.</p>
<h4>Scope and structure</h4>
<p>So my original idea was to pull some data from <a href="https://psnprofiles.com" target="_blank" title="PSNProfiles">PSNProfiles</a> player pages and let the user pick a player and view their data. PSNProfiles is a website that presents information about the games played and trophies earned by players on PlayStation 3, PlayStation 4 and PlayStation Vita. I'm a bit of a 'trophy hunter' and have been a fan of the PSNProfiles interface for a few years now. Not long after the initial idea came to me, I decided to add more data and allow the user to choose what to view. Then I decided to add a feature for comparing two players. Then a friend (a fellow PlayStation gamer and coder) suggested adding an option to export (individual player) data to XML or JSON. Why not? Then I decided to add the ability to change the player without restarting the app. The final interface of the app is structured as below.</p>
<ul>
<li>Choose player</li>
<ul>
<li>View data</li>
<ul>
<li>Basics</li>
<li>Totals</li>
<li>Summaries</li>
<li>Length of service</li>
<li>Collections</li>
<ul>
<li>Recent trophies</li>
<li>Recent games</li>
<li>Rarest trophies</li>
</ul>
</ul>
<li>Export data</li>
<li>Compare with another player</li>
<li>Change player</li>
</ul>
</ul>
<p>Navigating through this structure, as well as user interaction and scraping, viewing and exporting data, is handled by three classes - CommandLineInterface, Player and Scraper - and a (very basic) executable file.</p>
<h4>Challenges</h4>
<p>In my last blog post (linked above), I spoke about how engaging I found the challenge of building tic-tac-toe with AI and various CS50 problem set solutions. I find that challenge and working out how to build things with methods and approaches I haven't yet learned the tools to fully execute really drive my desire to keep coding. This project had far too many challenges to cover them all in great detail, so below I've summarised a few in three different categories.</p>
<h5>Beyond/across classes</h5>
<ul>
<li>Project set up and working in a local environment: working out how the Gemfile and environment.rb files should be configured and what terminal/command-line interface commands need to be executed to get things going both for me as the developer and for users<br><br></li>
<li>Validation</li>
<ul>
<li>Validating user input in menus and app functions<br><strong>Solution:</strong> using <code>until</code> and <code>puts</code> to guide the user to provide valid input<br><br></li>
<li>Validating that a player profile exists and has public trophies<br><strong>Solution:</strong> identifying page content or HTML elements that are unique to each case of an invalid or unscrapable player, and referring the user to the README for reasons a real player might not yet be scrapable<br><br></li>
<li>Validating that a directory exists in the export function<br><strong>Solution:</strong> using <code>Dir.exist?</code><br><br></li>
</ul>
<li>Returning to the CommandLineInterface's main menu from sub-menus and app functions within the Player class<br><strong>Solution:</strong> passing in the instance of the CommandLineInterface (<code>self</code>) as an argument/'cli' parameter when moving to the Player class, so calling <code>cli.main_menu</code> would return to the same instance of CommandLineInterface, in turn retaining knowledge of the Player instance(s) it should work with</li>
</ul>
<h5>Scraper</h5>
<p>Scraping was the first challenge I decided to tackle in building this app. Much of this was just like the scraping labs I'd already completed: take a URL, have Nokogiri parse it, then grab what you want by working out what HTML/CSS element, class, attribute, parent/grandparent element or any combination of the above distinguish the data you're after from the rest of the page. However, as the scope of the project grew, the extra data sources brought in a few different challenges, as outlined below.
<ul>
<li>Scraping a series of data - recent games - and then iterating over it to collect the first 12 instances, or less if there are fewer than 12 instances<br><br></li>
<li>Scraping fields or elements that appear on some profiles but not others, or provide different types or formats of data dependent on the game or player's activities, then storing and displaying data of different classes within the same field/attribute<br><br></li>
<li>Changing the format of multiple different scraped dates<br><strong>Solution:</strong> using the DateTime class to parse the text and store it as an instance of that class, then using its <code>strftime</code> method to display dates in my preferred format</li>
</ul>
<h5>Player</h5>
<p>When the scraper was finished, I had a hash with around 30 key-value pairs, and further hashes and arrays nested within. Challenges that arose in dealing with this complex data structure and other aspects of the Player class are detailed below.</p>
<ul>
<li>Creating readers to account for all the top-level and nested data<br><strong>Solution:</strong> adding all the attributes to an <code>attr_accessor</code> line, then combining the resulting reader methods with metaprogramming using <code>send</code> to assign all the top-level data to instance variables. For nested data, manual reader methods that use the top-level/instance variable readers and then dive deeper<br><br></li>
<li>Dividing the wealth of data up into sensible and not overwhelmingly large groups to present to users, and interpolating everything into <code>puts</code> statements with clear, user-friendly presentation<br><br></li>
<li>Exporting to XML/JSON</li>
<ul>
<li>Accounting for the different ways a user could specify a directory, in particular whether they include a slash at the end<br><strong>Solution:</strong> checking the last character of the user's input by calling <code>[-1]</code> on the string, then adding a slash if there isn't one<br><br></li>
<li>Transforming instance variables (back) into a hash to pass into the export methods<br><strong>Solution:</strong> using the <code>instance_variables</code> method on <code>self</code> to get all the instance variable names, then iterating over them, removing the <code>@</code> and collecting the result of <code>instance_variable_get</code> into a new hash<br><br></li>
<li>Not overwriting files if the user has previously exported a player's data<br><strong>Solution:</strong> using <code>File.exists?</code> to check if the default filename exists in the directory, and if it does, finding a number that can be appended that won't also result in an existing filename<br><br></li>
</ul>
<li>Working with two Player instances at the same time to <code>puts</code> the same data for each instance side by side</li>
</ul>
<h4>The result</h4>
<p>The result of navigating all these and more challenges - and putting in the hours to work through the less challenging but equally time-consuming task of building out all the methods to deal with scraping and displaying all the data - can be seen in the demo below. You can also check out (and clone) the <a href="https://github.com/yndajas/PSNProfiles-player-scraper" target="_blank" title="PSNProfiles player scraper GitHub repository">project code on GitHub</a>.
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/l1yA_LfLz-c" width="100%" height="100%" frameborder="0" style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasSoon after completing my implementation of tic-tac-toe with AI for a Flatiron lab, it was time to start working on my first major independent project. In the last couple months, a lot of my time has been taken up with moving and settling in to a new flat. Before the move I was only a few lessons and labs away from the project, and I think the feeling that I might have forgotten how to work with Ruby combined with not really having a sense of the required scale of the project led me to start procrastinating put my return to the bootcamp off a little bit longer than I really needed.Coming to coding, chasing the challenge and tic-tac-toe with AI2020-10-04T00:00:00+00:002020-10-04T00:00:00+00:00https://yndajas.co/coding/2020/10/04/coming-to-coding-chasing-the-challenge-and-tic-tac-toe-with-AI<p>This is the first in a series of posts I plan to write about my own journey of learning to code.</p>
<h4>Coming to coding</h4>
<p>Last February, I decided that my PhD and academia weren't really working out for me and that I needed to take a step back. Somewhat ironically, both my first book chapter (in 'Non-Binary Lives: An Anthology of Intersecting Identities') and my <a href="https://www.budrich-journals.de/index.php/insep/article/view/35952" target="_blank" title="Sexuality in a non-binary world: redefining and expanding the linguistic repertoire">first academic journal article</a> [<a href="https://www.budrich-journals.de/index.php/insep/issue/view/2731" target="_blank" title="Positive non-binary and / or genderqueer sexual ethics and politics">issue</a>] ended up coming out this year. I have no regrets about putting my PhD on pause, but this and other publishing activity did go some way to reinvigorating my interest in research and writing. Part of what motivated the journal article, and what makes me want to write more, is identifying a problem and creatively and rigorously working through it to find or propose a solution - or just ask further, important questions. That's the approach I took to identifying how and why we might expand the language (and underlying conceptual frameworks) of sexuality to recognise the diversity and mesmerising complexity of gender beyond (and within) the binary. A fondness for that way of thinking and working - creative problem-solving - is also partly what drew me to coding. The experience I've had with markup and particularly statistical programming languages in the past has filled me with the feeling that this is the kind of work I could do all day and not get bored.</p>
<p>Soon after taking a step back from academia, I started looking into coding bootcamps, eventually settling on Flatiron School. My plans for starting their software engineering bootcamp moved backwards and forwards as a result of employment and the COVID-19 pandemic. In the end, I decided to go self-paced and start this summer. After feeling relatively unchallenged by the first few modules and reading about a well-reviewed and free online computer science course, I also decided to pick up Harvard's CS50.</p>
<h4>Chasing the challenge</h4>
<p>One thing that struck me after week one (or 'week 0') of CS50 was that after being presented with a problem, it's up to you to work out almost all of the logic of implementing a solution... in C. The scaffolding and safety of Ruby's many in-built classes and methods (and those brought in through gems) swiftly fell away, leaving me to learn how to scale a building all on my own (where are the radioactive spiders when you need them?). That extra challenge - perhaps unsurprisingly - made me want to complete the harder problem sets (and then the easier ones after!). There's something deeply enticing about having to work out functions for seemingly simple tasks like calculating the length of a string and checking whether a number is odd or even, and then stringing such functions together to implement solutions to larger problems such as validating a credit card number using Luhn's algorithm, determining the readability level of a passage or dynamically ciphering text.</p>
<p>That feeling of real challenge started coming through with Flatiron as the curriculum began to delve beyond the surface of object-oriented programming. For most of the coding labs, you tend to be guided towards a solution either through explicit instruction or by a well-built test suite (the merits of test-driven development become clear early on). It wasn't until near the end of the object-oriented Ruby module - just before the first major independent project - that I encountered a lab that I really needed to spend more than a day on: tic-tac-toe with AI. The lab is intended to be done in pairs, but as a self-paced student with an irregular schedule and an appetite for challenge, I decided just to go it alone.</p>
<h4>Tic-tac-toe with AI</h4>
<p>The task involves creating three main modes of tic-tac-toe: player vs player, player vs computer and computer vs computer. Starting with the test suite, everything seemed fairly straightforward. However, once you get to the AI part of the problem - i.e. the code to control the computer player(s) - much like in CS50, it's all on you. At first I thought about just doing the bare minimum - build some methods that play valid moves without regard to whether they were good (or the best) moves. That attitude lasted a few minutes - I <em>needed</em> to work out a way to make it more complicated. So I continued, researching unbeatable tic-tac-toe strategies (there's a hierarchy of moves you can follow in order to at least draw every game - more on this below), thinking through how I could implement these in code and ultimately learning new ways of using Ruby that Flatiron hadn't yet covered in order to perfect the AI.</p>
<p>The lab is prestructured to include Board, Game and Player classes, plus Computer and Human subclasses that inherit basic functionality from the Player class. The process of getting the test suite to pass involves building out these classes to the extent that the game works, but with minimal AI - the computer player simply needs to return a valid move. Building the user interface - i.e. the command-line interface elements - complexifying the AI to the extent that it can never lose, and deciding when to stop is up to you.</p>
<p>I decided to add one more class: GameController. This class handles asking the user for the number of human players and in single player mode, whether the human player or computer player should go first and who should use which token (X/O). It then creates a new game instance with these settings, and once the game is complete, offers to start a new game or quit. While this could have been incorporated into the Game class itself, conceptually I viewed the Game class as a model of games from start to finish, with what happens before and after a game falling outside of that model. Pre- and post-game control could also live within the executable file itself, however owing to the complexity of the setup process, it felt more logical to contain the relevant code within multiple methods of a discrete class.</p>
<p>As I've already indicated, the hardest part of building a tic-tac-toe app with computer players is working out how to program the AI logic. My research led me to the following hierarchy of moves. If you play whichever valid move is highest in the hierarchy, it's impossible for the opponent to win (though a draw is possible and indeed inevitable if the opponent follows the same strategy).</p>
<p class="before-list"><strong>Unbeatable strategy</strong></p>
<ol style="font-weight: bold">
<li>win: <span style="font-weight: normal">play a winning move</span></li>
<li>block: <span style="font-weight: normal">prevent a winning move on the next turn</span></li>
<li>fork: <span style="font-weight: normal">play a move that will opens up two winning moves (i.e. two lines with two cells occupied by your token and none by your opponent's)</span></li>
<li>block fork: <span style="font-weight: normal">play a move that will stop the opponent playing a fork</span></li>
<li>centre: <span style="font-weight: normal">play the centre cell</span></li>
<li>opposite corner: <span style="font-weight: normal">if your opponent has occupied a corner, play the opposite corner</span></li>
<li>corner: <span style="font-weight: normal">play a corner</span></li>
<li>side: <span style="font-weight: normal">play a side</span></li>
</ol>
<p>Much of this is pretty straightforward. For winning and blocking, check if two cells in a line are the same token with the other empty. For the bottom four options, check if specific cells are empty or occupied by your opponent's token. Forking and blocking forks, however, is where things get a lot more complicated.</p>
<p>For forking, the idea is that since the opponent can only place their token in one cell on their next turn, you can win on your next turn by creating a situation where there are two cells that they would need to block to prevent a loss. My solution involved checking which lines do not contain the opponent's token but do contain your own. I then iterated over these lines and added any valid moves (empty cells) to an array - if a valid move appeared in multiple lines, it would be added once per line it appeared in. I then looked for valid moves that appeared in multiple lines and if there were any, played one of them.</p>
<p>That might sound a little complicated, but the idea is relatively simple: if different lines each have one cell with your token, and they have a shared empty cell, playing that empty cell will leave only one (empty) cell without your token in both lines. The opponent can only block one of these, setting you up for a win on your next move.</p>
<p>The harder part was working out how to program the AI to block a fork. For hours I tried out multiple different methods that improved the complexity of the AI, but none of them fully accounted for every possible move, leaving exploits open to abuse. What I was missing was a way to simulate every possible next move and then check for forks, before reporting back which moves allowed a fork to be played. My eventual solution was to create a duplicate copy of the board, play each valid move in turn and check on the next move whether the opponent could play a fork.</p>
<p>Creating a duplicate copy of the board proved harder than expected - at first every approach I tried 'passed by reference' in one way or another, meaning my duplicate copy's cells attribute was the same object as the board-in-play's cells attribute. Changing the duplicate would change the original. Perhaps I could've come up with a messy solution where I made a change and then reverted it, but that <em>feels</em> wrong. Eventually my research led me to work out that I needed to create a ('deep') copy the cell's values (collecting them into a new array) rather than of the whole object or array itself, then create a new board and set its cells attribute equal to these values.</p>
<p>While on many occasions throughout this build I thought about moving on to the next lab, it was always at most a matter of minutes before my thoughts shifted to "but what if...?" and my screen shifted to Chrome, Google and eventually Stack Overflow. The drive to work through, creatively solve and learn from problems in the process of building <em>stuff</em> is I hope what will make coding a long-term pursuit, profession and - most of all - passion. Next stop: minesweeper?</p>
<p>You can watch a demo of the final result in action below and check out (and clone) the <a href="https://github.com/yndajas/ttt-with-ai-project-online-web-sp-000" target="_blank" title="tic-tac-toe with AI GitHub repository">project code on GitHub</a>.</p>
<p> </p>
<p style="position: relative; padding: 30px 0px 57% 0px; height: 0; overflow: hidden;"><iframe src="https://www.youtube.com/embed/_M3nB_ZpLBE" width="100%" height="100%" frameborder="0" style="display: block; margin: 0px auto; position: absolute; top: 0; left: 0;" allowfullscreen></iframe></p>
<p> </p>Ynda JasThis is the first in a series of posts I plan to write about my own journey of learning to code.Blossom2018-08-21T00:00:00+00:002018-08-21T00:00:00+00:00https://yndajas.co/poetry/2018/08/21/blossom<p>Supportive friends and family
<br>I promise to blossom
<br>Your love is like the finest of fertilisers</p>
<p>Trans siblings
<br>I promise to blossom
<br>Until we're not seen as a disorder, but cherished as a gift</p>
<p>Regressively exlusionary faux-feminists and other transphobes
<br>I promise to blossom
<br>Until you find yourself on the wrong side of history</p>
<p>Haters in the street
<br>I promise to blossom
<br>So that one day you can blossom too</p>Ynda JasSupportive friends and family I promise to blossom Your love is like the finest of fertilisersCall me by my name2018-07-29T00:00:00+00:002018-07-29T00:00:00+00:00https://yndajas.co/poetry/2018/07/29/call-me-by-my-name<p>It's 4:51 AM
<br>I've been fighting to update my name on a page
<br>For the past five hours
<br>Almost nonstop
<br>Coming up against the rigidity of Wikipedia editors
<br>Or should I say, Wikicops?</p>
<p>Like the police
<br>In a dispute between one of them
<br>And an innocent civilian
<br>They'll always favour their own
<br>Won't listen to reason
<br>Empathy lost
<br>Defend the authorities at all costs</p>
<p>Discuss
<br>Debate
<br>Argue</p>
<p>They say to change my name on a page about an event in 2015 is to change the past
<br>"We can't rewrite history to make one person happy"
<br>"This is a matter of historical accuracy"</p>
<p>Well I'll tell you what's accurate:
<br>Deadnaming can lead to
<br>Gender dysphoria can lead to
<br>Mental distress can lead to
<br>Depression can lead to...
<br>Worse.</p>
<p>And I'll tell you what's accurate:
<br>Throughout history I've been Ynda Jas
<br>Simply known by a label of the past</p>
<p>Yet records are final
<br>You rigidly rule
<br>And for naming this violence
<br>You paint me for a fool</p>
<p>Discuss
<br>Debate
<br>Argue
<br>Cause lost</p>
<p>Call me by my name
<br>Such a simple task</p>
<p>Call me by my name
<br>Is it really so much to ask?</p>Ynda JasIt's 4:51 AM I've been fighting to update my name on a page For the past five hours Almost nonstop Coming up against the rigidity of Wikipedia editors Or should I say, Wikicops?