Sunday, March 17, 2024

Adding alternate sites for the NPB; thanks, JapanBallTickets.com

Japan's professional baseball league, NPB (Nippon Professional Baseball), is near and dear to my heart.  I first visited in 2016 and was captivated by the crowd and atmosphere at a game in Hiroshima between the Carp and the Tigers.  My wife and I sat in the visitor's "performance" section with the Tigers' supporters at Mazda Stadium, and they could not have been friendlier (or rowdier!).  Since then I've been back to see games in 2018 at Meiji Jingu Stadium in Tokyo, in 2019 at the Fukuoka PayPay Dome and Koshien Field, and in 2023 at the Tokyo Dome.  It's always been a delight to catch one of these games and marvel at the atmosphere.

It was really important to me to get the NPB schedule data right; some games take place at alternate venues across the country (for example in Akita, Okinawa, and Kumamoto), and I wanted to represent those correctly on the map.  Enter Michael Westbay, the brains behind JapanBallTickets.com; he was kind enough to share his spreadsheet of ticketing data, which contains the correct locations for all games during the season.  After adapting his data, I'm happy to present correct alternate venue locations for NPB games in 2024:



This was something I really wanted to get right on the site, and it's nice to be able to do so.  As I write this, my primary data source has correct date/time info for games through May 29; after that, a few games have had their start times changed, but it isn't yet reflected in the data.  

As always, please verify start times and home venues with the home team before making travel plans and buying tickets.  

Have a great season and play ball!

Saturday, September 2, 2023

Improved filter performance; implementing custom hooks with react-query made it easier

I finally got some time to do a little work on sportsmap.world, and used it to work on improving filter performance in the frontend.

Working with getting start times for all these sporting events displaying correctly in their local time zone is actually a little tricky; it gets harder when you consider how to filter by date.  Midnight on September 2 in Seattle is different from the start time of September 2 in Italy, when you consider all the times I'm working with are normalized to UTC.  I had previously been doing a calculation at filter time to determine if the local start time for an event fell within the date filter range; by moving that calculation to the initial query function, I was able to improve query performance in the frontend.  

(Not a super-complicated perf improvement, but as with all software tasks, it's just a matter of finding the time and getting in the right mental space to work on it.)

One thing I have warmed up to is using custom hooks in React, especially in conjunction with Tanstack's react-query library.  One of my setup tasks for this perf improvement was to refactor two similar backend queries into a single custom hook with input parameters.  By tying into react-query's existing hooks for data, isLoading, isError, etc., I've been able to greatly reduce my own usage of useEffect, which makes for cleaner components.

A great combination I used on a recent work project: OpenAPI to define backend APIs, openapi-typescript and openapi-typescript-fetch to turn the API into usable Typescript objects, react-query to do the querying and maintain loading state and show errors, and wrap it all up into a custom hook which can be re-used by multiple components.  A really clean solution, especially for projects where the frontend is stateless; that is, object state is the responsibility of the backend, which is an especially useful paradigm for microservice environments.

Monday, February 6, 2023

Big changes: more events starting with version 2 of sportsmap.world!

One of my goals with sportsmap.world was to be able to show the full, wide world of sporting events taking place around the world.  Not just the big events like the "Big Game" coming up next Sunday in Glendale, Ariz., but the small events, like the Everett Silvertips junior hockey team about a half hour up the interstate from my house.

I've had to dance around some of the limitations of my data source; simply put, I'm limited in the number of API calls I can make per month.  I can query each calendar day for events and updates, but only up to 1,000 calls per sport per month.  Most of the major events have venue information with lat/long locations attached to their event objects, but many more smaller events do not; this includes some leagues I wanted to represent on the map, including Japanese baseball (NPB), junior hockey across Canada and the U.S., minor league baseball, smaller soccer leagues across Europe and the rest of the world, etc.

For many summers as a kid, I would visit my dad in Great Falls, Montana; I spent several summer days at the local ballpark, watching the Great Falls Dodgers (now Great Falls Voyagers) rookie-league team.  It was something fun to do at a time when I would have been otherwise bored; I loved having the distraction, following the teams' budding young stars, and getting an up close seat of the action.  It was at one of these games, on a chilly, windy night, when I discovered my love for coffee (the ballpark had cups available for $0.25 each!).

I'd like for people who are traveling in an unfamiliar place to be able to see on a map where events are going on, no matter how small they are.  Now on the map, you can find really minor soccer leagues, lower levels of college basketball, college and junior hockey, and more.  I see these as "neighborhood" events; fun to check out if you're in the area, are bored, and want to see what sports looks like where you are.

One world of caution: to get the venues for these events, I'm querying for the home stadium of the listed home team.  This won't always be accurate; for example, my beloved Hanshin Tigers don't play all of their games at Koshien Stadium, even though that is how their home games would otherwise be listed (because my data feed lacks more specific venue information).  I'm considering ways to put a disclaimer on these events' venue information to call that out.  In other cases, I'm finding that the lat/long information for venues is not always correct; there are some typos in the data source.

In the meantime, as always, please verify the home venue and location before making travel plans for buying tickets.  Check the website of the league or hosting team, or consider calling or e-mailing them directly.  

Do give these teams and smaller leagues your support; in many cases they depend on live fan support and ticket sales to keep them afloat!

Tuesday, December 27, 2022

Map marker clusters and more user-friendly UI changes!

A big big thank you to open source developer Leigh Halladay, who published this useSupercluster hook for React:

use-supercluster npm package

use-supercluster Github page

I had been wanting to do map marker clustering using Mapbox and React, but hadn't found a solution until I stumbled on Leigh's library, described here.

This finally allowed me to cluster markers together, allowing me to publish sportsmap.world with a much friendlier interface for mobile users.  I've made additional changes to make the site more smartphone and mobile friendly, as that's the primary experience for most people browsing the web these days!

More UI upgrades since November:

- A better mobile calendar experience, including a dropdown calendar widget to allow you to select a date range, rather than relying on the double-date slider (which is still present for wider screen).

- A filter-by-sport widget, to remove specific sport pins from the map.

- Fast load times & optimized queries, plus a loading spinner while the initial query is in progress

Up next: I want to add way more events. My data source is sportradar; up until now, I've only been able to display events sportradar provides when they have venue information attached.  Many more events from sportradar, e.g. Japanese baseball (NPB) and minor soccer leagues around the world, do not have this venue information attached to their events; but, most of the time we can assume the event is taking place at the home team's stadium, which is discoverable via additional queries.  To make this change, I'll be doing some work on the backend to move to the Prisma ORM, redesigning and adding some tables in PostgreSQL, and writing the logic to try to retrieve and store this additional venue information.  With luck we will see some NPB games on the map next season!

Meanwhile, I'll be diving back into the search for a new full-time job next week.  If you like what you see from the site, check out my LinkedIn profile to contact me.

Tuesday, October 4, 2022

Navigating the (React x Google Maps) Wild West

I wanted to try Google Maps in my React front-end, and figured that probably someone has written a React wrapper for Google Maps, or perhaps Google itself had taken it on at some point.

Here are some open-source packages that show up in an npm search:

  • react-google-maps, last updated five years ago but still gets 150k downloads/day.
  • @react-google-maps/api, a "complete re-write of the (sadly unmaintained) react-google-maps"
  • google-map-react 
  • google-maps-react 😂
  • @google-maps/react-wrapper
  • simple-react-google-maps [Sure, Jan]
  • react-maps-google [Now I'm just annoyed]
  • react-hook-google-maps [For those of you addicted to custom hooks for everything]
  • react-google-maps-loader 
  • react-static-google-map 
  • google-maps-react-17 [I guess the 17 is for React v17? Great, that will never go out of date]
  • google-maps-js-api-react

There are more, of course.  I feel like I'm in NYC looking for real Original Ray's.  Or maybe touring a graveyard.

So!  This is frustrating for a number of reasons:

  • They all solve the problem slightly differently, so the resulting React code can look vastly different depending on which one you use.
  • Looking for help on Stack Overflow or Google is difficult, because I keep winding up on help for a different repository.
  • The varying degrees of unmaintainedness [new word copyright me] of these repositories by their owners makes it hard to pick one; and I don't have a whole lot of faith that the one I pick will be maintained long-term.
  • My ultimate solution doesn't feel very React-like.  A lot of these packages tackle the simple case of adding a map element and some markers, but I wanted to go a little further than that by clustering close-together markers and adding a search bar.  I would expect to be able to add child elements to a parent map element that do that, but could not find a package that gives me that option.  I think I have a solution that works, but it involves creating a React useRef hook to manipulate the map object directly; not very React-y, definitely feels like I'm breaking some rules.
  • I'm sure there's a React developer out there who will say, "Oh of course you should use react-maps-google, you fool!  It's obviously the best one!"
I like React for simple things, and it's been good for quickly building up my frontend, but often when I get into more complicated scenarios, finding the correct path forward is non-obvious to say the least.  And this is a framework that came out nearly 10 years ago!  There have been so many fundamental changes to React that it's hard to keep up with the latest best practices, and among the community there seems to be a lot of disagreement on that anyway.  This situation with the dozen-plus possible Google Maps packages feels like more of the same chaotic soup.

Wednesday, September 21, 2022

Version 1.2.0 is live

 A few minor improvements:

  • Added a Mapbox search widget (called a Geocoder in code), which allows you to search and zoom the map to a destination.  Useful to search for sporting events near a specific landmark, hotel, address, etc.
  • Changed some data query profiles around so that events coming up in the upcoming week and upcoming month get refreshed more frequently.  (As always, check with official league and/or team online resources to verify up-to-date event venues, dates and times.)
What I'm working on next:
  • There are a couple of things Mapbox doesn't lend itself well to, especially for the mobile experience; I'd like to be able to group map pins together, for example.  Also I'm finding some locations aren't up to date in the search box (Seattle's Lumen Field is still called CenturyLink Field, for example).  I'll be experimenting with Google Maps' API to see if I like the user experience better (and also if I like the React developer experience any more or less!).
  • Some other UI elements need to be improved for the smartphone user experience, which is the dominant one these days.
  • The filter widget could use some alternate method to easily pick dates, like a calendar widget.  Will be looking around for one of those.
  • Filtering by sport would be nice.
Another future backlog item:
  • My data source has info on a lot more events that don't have venue location information attached.  I'd like to come up with a way to show a pin for the assumed venue based on the home team; this is going to take a little work to make sure I get it right.  If I can get it work, I can greatly increase the number of leagues and teams I show (for example, Japanese professional baseball, minor league baseball in the US, WNBA, etc.).  Ultimately I'd like to even show lower-league soccer; sometimes there's a team playing in your neighborhood and you wouldn't otherwise know it!  That could be a fun way to spur local community interest in more minor leagues and teams.  (Or, help you figure out something fun to do outside of the house when you're visiting relatives over the holidays...?)
Enjoy and beinvenue au monde sportif, bon voyage!

The perils of React

This was a great article on React that popped up in my Reddit feed:

I have my own feelings on React and the generally complex state of front-end web development today.  

I've worked on a lot of front-end code since 2013; we started bringing in React around 2015 and I immediately found it just really confusing. I've got a little better handle on it now, just built my own website (sportsmap.world!) with modern(-ish?) React and Typescript, which seems like generally a good combo for medium-complexity sites. I do like how the code looks with functional components and hooks, and I was able to find a library that wraps my map provider's components with React objects; it generally works pretty well.

But I agree with a lot of the points in the article, especially:

- Having to know the "Rules of Hooks" is bad; the rules should be more intuitive, or easier to spot or have called out at development time

- Having to read a dissertation on a hook to use it "properly" is bad

- Everybody's opinion of "properly" seems to be different

- The framework is bad at letting me know I'm doing it wrong

- Having to list out dependencies should be unnecessary

- Debugging rendering performance issues is painful, the solutions are usually non-obvious

- Outdated documentation, outdated code bases and packages, outdated Stack Overflow answers are all a huge problem.

And then just generally the whole thing about state management. This is a framework that updates my components based on changing state, but it just does not natively handle state well, for any site that's more complex than a few components. The fact we need to bring in some external package like a Redux to attempt to handle it feels like a massive shortfall.

I was indeed handling this stuff just fine on my own back in the day with MVVM organization and jQuery, and navigating these hurdles often doesn't make React feel like an improvement.

And then yeah, there's the fact that it's a Facebook joint; what if Facebook one day just decides they're going to up and charge to use the license? Doesn't feel far-fetched in 2022 when Meta is seeming to struggle to maintain its relevance.