An online markdown blog and knowledge repository.
Semi-regular notes taken during my software developer journey.
I've been considering changing-up this semi-irregular blogging style note taking for something that will be more helpful when I need to reference it in the future. While it is good for me (generally) to continue to write about my experiences in tech, the future me usually gets frustrated searching through past-me notes because the solutions aren't always documented in a reproducable way. This will take some time to sort out, and will be part of what I hope will be a slight reconfiguration of my routines and methodologies, so I can continue to improve and not get stuck in any ruts.
The Mobile Weather App color and theming and tabbed-based navigation have been implemented and there appear to be very few issues. Next step is to produce a point build for on-phone testing (upgrading the current point-release version) and moving forward with the next goals for the app. Hopefully I'll have the app in a useable state before the end of January 2024. Meanwhile, I have several other tasks to accomplish especially around the house here, so I have plenty to do!
Happy new year!
I managed to work through designing a functional Merge-Sort algorithm, started yesterday, and lots of sketching and planning then and this morning, and my custom-designed Jest tests are passing. However, it does not pass the same test when run on the FreeCodeCamp webpage. Not sure what that is about, but I'm going to move on to other challenges so I don't get stuck.
The next challenge was Binary Search. This wasn't too difficult, but I could not complete it within 45 minutes so it is difficult to say if I'd complete it during an actual technical whiteboard session.
Compared TabBar and Flyout Shell view implementations for my mobile weather app.
The TabBar implementation is closer to what I envisioned:
The problem is it does not support custom color images and instead relies on black and white or font-based icons.
Flyout seemed to be a good enough fit and actually has a few perks that TabBar does not:
Started redesigning the weather app navigation, with the goal of including a navigation bar at the bottom of the app. This requires designing some icons, updating AppShell, among other things.
Completed Quick-sort and Insertion-sort at FreeCodeCamp.
Quick-sort is a divide-and-conquer algorithm that utilizes recursion to split values within the array between larger-than, and smaller-than values. A pivot value
is determined (carefully) so that all values greater than or equal to it are moved into a right
array, and those lower than it are moved to a left
array. The reason the pivot is so crucial is a poorly selected pivot will allow the recursive calls to exhaust the stack, rather than pick sets of values to put into each sub-array (left and right). Until today I wasn't aware of the Big O complexity in time of spread syntax
(aka spread operator) in JavaScript, but I assumed it would be no worse than simply iterating over each array that I intend to merge. According to this StackOverflow conversation, it is O(n) in time.
One hurdle was determining how to define a sensible pivot. It took a while to find one that would work on the small datasets i was working with:
// two items in the array and not the same number
let pivotVal = ((array[0] + array[1]) / 2);
// three or more items in the array
let last = array.length - 1;
let pivotVal = ((array[0] + array[1] + array[last]) / 3);
These codelines are not necessarily robust solutions for any input, but they worked for the existing data-sets. For a more robust algorithm, it would be beneficial to use a randomized value, or a more mathematically-derived number, given all values in the array.
As an aside, I ran into a sub-challenge where JavaScript would treat a single-item array in a function argument as a String or Number instead of an Array. Before I gated the Quick-sort function with a minimum 2-item array limit, I was forcing a re-cast or verifing the Type
ahead of taking actin on the input:
function func1(inputArr) {
if (inputArr.length == 1) {
if (Array.isArray(inputArr)) {
...
}
...
}
...
}
Insertion-sort is a small, stable sorting algorithm that also utilizes a common value-swapping algorithm. Frakly, it is easy to confuse this one with Bubble-sort, however it tends to sort items toward the "left" side of the array rather than buble high-values up to the top. Time effeciency is O(n^2) and space O(1), and is good enough for small arrays so it can easily be used as an alternative to another algorithm or perhaps as part of a recursive portion of a larger sorting algorithm.
After struggling with the NWS API for several hours, I discovered it has experienced a partial outage. Being relatively new to the API, I wasn't sure my code was doing the right things so I was focused on debugging and other troubleshooting steps. The NWS says the partial outage will continue until early 2024, so development on the weather app will be on hold for at least another couple weeks.
Meanwhile, I completed several FreeCodeCamp challenges including a bubble-sort algorithm.
Bubble-sort Key Takeaways:
private static void BubbleSort(int[] arr)
{
...
while (unchanged == false)
{
...
if (idx+1 < arr.Length && arr[idx] > arr[idx+1])
{
// this is a common swapping algorithm
int temp = arr[idx];
arr[idx] = arr[idx+1];
arr[idx + 1] = temp;
itemSwapped = true;
}
// track the inverse of itemSwapped outside of the swapping loop
unchanged = !itemSwapped;
}
return; // in-place array sorting algorithm
}
Working on adding NWS Alert information to the mobile weather app. One approach has been devised in a separate dev/test project. I also explored using Google's Geocoding API to get Lat/Lon for a city name. The API isn't perfect (and in fact the API and the JSON output are both fairly complex), but for most common US city names it works well enough. I might look into alternatives or skip requesting a city name and instead try to use a map-based geocoding solution. MAUI 8 appears to have library functions that will help with that.
The basic idea for gathering and displaying any weather alert is to:
An alert JSON object is actually an array of objects, so in the event there are multiple alerts my app will need to iterate through them all and ensure readable output to the mobile app UI.
I've been wanting to clean-up some of the code and UI look-and-feel in the mobile weather app:
Another feature that needs to be implemented: Applying secrets and configuration to the app. If I'm going to use my own secrets, I don't want to store them with the code.
Now I've been humbled: While exploring the NWS API some more, I've come to realize my weather app is looking at only forecast data and not current conditions or observation station data. I'll be able to use the existing code for the most part, but I will need to insert the current observations code into the app and move the forecast data to other pages. This means navigation will be necessary, so I'll have to start working on navigation sooner than later.
Completed initial color scheme and light/dark theme implementation for the mobile weather app. Some key takeaways:
The mobile weather app has been deployed a few times for Android now. Here are some take-aways:
Time is going by pretty fast. Lots happening the last week or so slowed or blocked coding progress. Nonetheless I eeked out some time to:
What I've learned while exploring the .NET MAUI Community Toolkit:
OnAppearing
and OnDisappearing
.Future .NET MAUI Community Toolkit exploration:
One of the challenges of designing a MAUI app is how to handle platform-specific actions, such as accessing Location Services. Windows, macOS, and iOS all handle such features differently and they are not completely abstracted in the framework. So #if
#else
and #endif
statements must be sprinkled through the code so that these platform-specific calls can be made when they return true, e.g. #if ANDROID
.
I experience some challenges in this context:
/soapbox
A few days ago I completed an MS Learn training module "C# Null Safety" and added my thoughts.
I've had a few adventures in MAUI over the last several days. Here's an overview with key takeaways:
MAUI build definitions return binary executables, not DLL libraries, because it is building for platforms. A Test Project wants to consume a DLL to perform tests against, so a couple things need to happen besides just making the target project a dependency:
More on this as I work on unit testing MAUI in the future.
The API requires the caller to include custom Accept and UserAgent headers to define application/ld+json
and (its just me, name@email.etc)
identifiers. There is no API Key at this time (although the documentation promises that will be necssary "in the future"). This is true of the several endpoints I have worked with so far.
One call has perplexed me, however. Here is an overview of my movements through wondering, confusion, and finally realization:
<Image>
elements accept a Source=""
property that tells the Image class where to look to 'load' the image. It could be a local file, a Stream
type (which is an abstract class and can only be "looked at" once), or loaded as an HTTP request. But what about custom headers?? The API documentation noted that the /image
end point was deprecated. How could that be? It's in their ld+json
response?!?/image
endpoint required the same custom headers. It does not.source=
and HeightRequest
). Despite MAUI being able to process a REST Response stream, I believe the problem has to do with the undefined content type.One additional note: I tried to leverage the MAUI Lifecycle eventing system, but the associated ViewModel was already inheriting ObservableObject (for simplified property update notifications) and in order to register and consume Lifecycle Events it would need to inherit from Window. Multiple inheritance is not supported in C#, and I wasn't willing to factor-out the ObservableObject inheritance to create a base implementation to provide the capability. That's okay, I don't need to leverage lifecycle events just yet.
Started looking into enabling the Android built-in location capability. Since this might take a while, and right now the app is working and looks okay, I also initialized a GitHub repo to track changes, helping me to document actions going forward, or roll-back dev branches that don't need to be completed.
More investigating MAUI Mobile Weather App design and implementation: Using DI and a collection based on Collection<T>
, in conjunction with an MVVM design model, data from a web API can added to a page. The Collection base class provides generic storage of custom Types - value or reference, includes an indexer, and implemented methods following IList and IEnumerable interfaces (among others), like Add, Clear, IndexOf, Remove, and several more.
I ran into a common issue in MAUI when leveraging Dependency Injection: "Missing default constructor for {viewModel name}". This happens when a new constructor is implemented. MAUI ContentPage.BindingContext expects a ViewModel codepage to have a parameterless constructor for initializing the object. The error also mentions a missing type converter.
For example, instead of doing this:
<ContentPage
...
>
...
<ContentPage.BindingContext>
<viewModels:MyViewModel />
</ContentPage.BindingContext>
...
...remove <ContentPage.BindingContext>
element(s) and update the DI Container (in MauiProgram.cs) to register the Views and ViewModels:
...
// add the view
builder.Services.AddTransient<MainPageView>();
// add the view model
builder.Services.AddSingleton<MainPageViewModel>();
...
...and then add to the code-behind of each registered View, a BindingContext assignment to the CTOR-injected view model:
public partial class MainPage : ContentPage
{
public MainPage(MainPageViewModel viewModel)
{
BindingContext = viewModel;
InitializeComponent();
}
}
Dealing with Null values and Nullable Types:
public class ReceivedApiObject
{
// when the API responds with null value types the class can be instantiated
// and its members called without having to catch NullValueExceptions
public string? UnitCode { get; set; }
public int? Value { get; set; }
public override string ToString()
{
// check for null and use a temporary value type to store an appropriate value
string tempUnitCode = string.IsNullOrWhiteSpace(UnitCode) ? ":null" : UnitCode;
// same for the Value property
string? itemValue = Value == null ? "null" : Value.ToString();
// trim the temp value without mutating the source property
string fixedUnitCode = tempUnitCode.Substring(tempUnitCode.IndexOf(':') + 1);
// return values despite possible null Properties
return $"{itemValue} {fixedUnitCode}";
}
}
}
public class AnotherApiObjectThatReturnsAnDouble
{
public string? UnitCode { get; set; }
public double? Value { get; set; }
public override string ToString()
{
// Similar idea here as to the previous example
string tempUnitCode = string.IsNullOrWhiteSpace(UnitCode) ? ":null" : UnitCode;
// again, avoid mutating the Properties
string? itemValue = Value == null ? "null" : Value.ToString();
string fixedUnitCode = UnitCode.Substring(UnitCode.IndexOf(':') + 1);
// return the replacement value as soon as possible
if (itemValue != null && itemValue.IndexOf('.') < 0)
{
return $"{itemValue} {fixedUnitCode}";
}
// in this case I only want no more than 2 hundredths decimal places
string trimmedValue = itemValue!.Substring(startIndex: 0, length:itemValue.IndexOf('.') + 3);
return $"{trimmedValue} {fixedUnitCode}";
}
}
When these code blocks run, and either UnitCode or Value are null, they are replaced with a printable string value that should be safe for the calling method to use. The actual returned values also provide evidence of null-returns without having to catch an Exception.
Completed "Get Started with C#" learning path hosted by Microsoft Learn. Also passed the FreeCodeCamp Foundational C# with Microsoft Certification Exam with a score of 90% in 40 minutes. There was at least one question that was not covered in the course content, and three other questions that were not phrased well and/or the "best answer" didn't appear to be syntactically correct. Glad I did it, and will continue to look for other opportunities like that one.
Back to work on the MAUI Weather App. I discovered my REST call Headers were not quite right, so I was getting JSON back that was more difficult to work with than I had hoped. All of my models needed to be updated so that the parsing mechanism can capture the data properly. Next step is to rework the Page ViewModels to correctly use the model data, and go from there.
I've been watching .NET Conf 2023 videos and working through more MS Learn Modules focused on C#.
Today's most interesting .NET Conf session was on .NET Community Toolkits. These toolkits could be useful for my mobile weather app and the future file sync tool v1 projects.
Open source collaboration is welcome:
In between other tasks I worked through Copilot Adventures to gain more experience with GH Copilot and learn a few things. I still need to get Copilot to write tests for me (my last attempt resulted in a non-functional test project in VS Code) but I'll work around that in Visual Studio and try again. Key lessons:
An example of the last point: Printing emoji to a Console window requires a little know-how and some visual padding.
// this icon will take up a certain amount of character space
public static string DragonIcon => "🐉 ";
// this icons takes up a certain amount of character space
public static string AlphaCharacter => "a ";
// net result of printing 3 of each:
🐉 🐉 🐉
a a a
// the Console class must be configured to display UTF8 or other non-standard encoded characters
Cosnole.OutputEncoding = System.Text.Encoding.UTF8; // for the dragon icon above
// then the spacing must be fixed for the output to line up in an expected way
public static string AlphaCharacter => " a ";
// net result of printing 3 of each:
🐉 🐉 🐉
a a a
// note: the MD rendering environment does not do the demonstration any justice.
Tomorrow through Thursday is .NET Conf 2023! I'm looking forward to seeing what .NET 8 and the latest release of C# have to offer.
Completed a few code challenges provided by MSFT Reactor - CoPilot Adventures. The purpose is to exercise using GitHub CoPilot and learn some of its commands and capabilities. For example:
CTRL + i
opens the command window./doc
: Create code documentation. This is pretty good./fix
: Attempts to fix problems with code. Occasionally this overrites perfectly good code that isn't related to the problem. Pay close attention while using it./explain
: Explains what highlighted code does. This is fairly good, but it seems to give-up on occasion without providing a response. Trying again later usually works./tests
: Generate unit tests for the highlighted code. This seems a little wonky and it doesn't do any setup like creating a test Project, installing dependencies for the test type (XUnit et al).Completed a code challenge developing a custom Stack. I wasn't able to write any code after designing and analyzing a solution so that is a failure. However, it's been some time since I've challenged myself in this way. A few hours later I wrote the code solution using TDD and within about an hour had a working library with unittests.
Accessing the filesystem can be tricky. There are things to remember:
using()
. This is the recommended method per Microsoft..Close()
at the end.// this function creates a new file and adds data to it while respecting the Dispose() pattern
private void CreateFile(string filename, byte[] utf8buffer)
{
using (System.File.IO.FileStream fs = File.Create(filename))
{
fs.Write(utf8buffer, 0, utf8buffer.length);
}
}
// this function creates a new file and closes so another process can access the file
private void CreateFile(string filename)
{
System.IO.File.Create(filename).Close();
}
Finished up some initial "V1" planning for the sync tool. There are some challenges to overcome, but nothing a little planning ahead and maybe some additional design drawings and test-driven development can't help out with. Some takeaways:
[]
selector expression taught me to implement the same behavior on a custom Collection. The danger is the keys will be infinite, so boundaries must be set around the code and it's callers. Code is below.Implement Dispose pattern through existing Class
. It is only necessary to deploy the full Dispose() pattern on a custom class that doesn't already implement it. Code example below.IComparable<T>
and IEqualityComparer<T>
. Turning to C-Sharp training from Bellevue College, I found the answer. Code is below.Indexing with a string instead of an integer:
public class MyWrapperClassCollection : IList<MyWrapperClass>
{
private IList<MyWrapperClass> _myWrapperClasses
public MyWrapperClass this[string name]
{
get
{
foreach (MyWrapperClass item in _myWrapperClasses)
{
// MyWrapperClass has a Name method that returns a unique string for an instance
if (item.Name == name)
{
return item;
}
}
// This is where the caller needs to have an exception handler.
throw new KeyNotFoundException($"{name} not found in collection");
}
}
}
Implementing IDispose() pattern on a wrapper class:
public class MyWrapperClass : IDisposable
{
private SomeClass _someClass; // SomeClass implements IDisposable
public void Dispose()
{
Stop();
Path = string.Empty;
Filter = string.Empty;
((IDisposable)_someClass).Dispose();
}
}
Implementing Equals() override method:
public override bool Equals(object? obj)
{
if (obj == null)
{
return false;
}
// use a cast to enable comparing instance properties
MyWrapperClass other = (MyWrapperClass)obj;
if (this == other)
{
// the items are the same
return true;
}
if (this.Name == other.Name && this.Size == other.Size)
{
return true;
}
return false;
}
Alternatively, it could be necessary to include a test comparing references between this
and obj other
:
// method bool accepts two parameters (object a, object b) and cannot be overridden
Object.ReferenceEquals(a, b);
// NOTE: 'interned' reference types will not evaluate properly, nor will boxed value types.
Anyway, I have completed building a small Library that can serve as a model for the future sync tool, that includes disposal, collections with enumerators, equality checks, and unit tests. This work should put me on a good path toward a well-built synchronization tool.
Recorded videos of the setup and usage of the sync tool, demonstrating the expected straight-line workflow. After several run-throughs of the presentation deck and recoding these videos, I updated the README file because I realized it was not very concise in a few spots, and actually needed some minor corrections to be helpful.
It turned out to be a blessing that I recorded videos of what I had planned to demo, because my webcam wouldn't record video of two PCs with any clarity (just a cheap web cam), and my main computer was not allowing installation of Winlink Express to run Zoom and the demo there, instead.
The attendees were understanding, and the slide-deck presentation and demonstration went well, along with a little Q and A before 45 minutes was up. We went long with additional Q and A and basically agreed to go forward with the project!
I spent half of yesterday handling administrative tasks that needed attention, and stuff around the house too. As for coding, some key takeaways:
Type
s that the .NET library System.Text.Json
could easily handle. In many cases I needed to use custom classes to handle what looked like IDictionary
items or Tuples
.Nullable
Types when possible, adding ?
and the [AllowNull]
attribute to classes where necessary. You cannot trust that API data will have values at all elements!Some better practices to use next time I have to work with deserializing JSON:
Working through the MAUI Weather App again. There was a bug that kept crashing the app, and it was inconsistent. Here are my key takeaways:
int
or string
), collections [ ]
of things, or other specific objects that contain other properties. An example JSON file where not everything is a string: { "@context": [ {...}, {...} ], "gridId": "SEW", "gridX": 128, ... }
. 128 is a Number type, not a String type.System.Text.Json
makes Serializing and Deserializing JSON and Objects fairly straightforward. Just watch out for camelCase vs PascalCase, and for the Type of each entry: String, Collection, or Number (see above).As it stands right now, the MAUI Wx App is moving forward, albeit a little slower than I had hoped.
I received email back from key (to bo) stakeholders of another project I'm working on. At least 1 is interested in a demo. In the next few days I will walk through my demonstration using actual PCs to verify the demo script is good, and then try to record it for posterity. Perhaps next week a live demo will be done with some of the to be stakeholders.
Working with MAUI the last few days I have learned a bunch, after riding a roller-coaster of "this is easy and cool" to "does this really work?" to "what was I thinking?!?".
Key takeaways:
GoToAsync()
method.Resources\Images
and be sure to avoid dash -
characters in the name. Also, stick with png
files. Note: svg
files are converted to png
during build.Debug.WriteLine(string)
. Use the Output
window set to Debug
in Visual Studio to see the logged output.Style
configureations in a ResourceDictionary
to make controls interactive.Shell
class. Check out Are You Using DI In Your MAUI App Yet? for an enlightening walk through.The Mobile Weather app is now in a much better place than it was at any time over the last 2 days.
The last week has been very busy will getting ready for training sessions I am running over the next 4 weeks. Last weekend was the first one and it went well. Feedback during this first 'basics' class led to some changes in the presentation content and order, so the next group that gets that presentation will reap the rewards. The 'intermediate' class won't be until November, but I have a bit of work to do:
I also want to send out PDF'd certificates of accomplishment to everyone that participates, so I need to complete filling and sending these out for the basics class, and start getting them ready for the intermediate one.
In case that's not enough, I need to exercise my newly acquired .NET MAUI knowledge, so my plan is to start developing a small mobile Weather App. Whiteboard planning is just about done already. UI wireframing, the request/response cycle, and data handling all need to be designed and debugged before I can start coding.
Investigating the NOAA Weather API has been easy. Last year I tried this and it didn't make much sense to me but today, it is simple. My experiences building and utilizing APIs is paying off. There is even a Swagger-UI-like interface for the API. It isn't as well documented as I would like, but the data schema and examples are there, along with expected Result bodies and codes. The part of the documentation that is challenging is the NOAA syntax for zones, areas, and etc. I suppose that will become apparent after additional research.
The harder part will be sorting out what data is worth caching and ready for display, and what can be skipped over. For example, if the App displays the current conditions, and the user then wants to see the forecast for the week, that data should already be available either through an advanced query or the cache already has that info from a previous call (before the cache expiration). This will take a little more work on my part to figure out. If I keep focused on the simple answer, I'll find the right solution to implement, and will go forward from there.
Lots of project planning, emailing, and organizing going on the last few days. There are some good things coming up across the next few weeks including project presentations, and a few training session I will be leading. Lots more work to do (not enough coding but that will come soon enough).
Started working on initial plan for a MAUI mobile app for Windows + Android. The goal is to make an app that can be published to Google Play Store. Expected completion is by end of 2023. There are several other projects I am currently working on that will slow initial progress of this project, but as November wraps up I expect to be able to dedicate more time through December. I'm excited!
MSFT Learn took me down a strange trip as I worked through the Create Web Apps and Services with ASP.NET Core path. The learning tools they presented included React, Vite, and MaterialUI, as well as GitHub CodeSpaces. Nothing wrong with any of that, it was just unexpected given the context was ASP.NET - I would have guessed they would have done a Blazor or Minimal API framework for the training, instead.
At any rate, it was good to do that since I hadn't done much with React recently, and have not previously been exposed to Vite or MaterialUI, and had yet to take advantage of GitHub CodeSpaces. All good!
A lot of good information was contained in that module, including Front-End Development Concerns, Selecting a Design System, and SPA Frameworks.
In C#, Casting to a specific type truncates rather than rounds the value up or down:
int numerator = 5;
int denominator = 2;
int total = (int)numerator / denominator;
// total will be 2
Working through more training modules. Key takeaways:
WebApplication
class now has MapGet()
and other HTTP verb-suffixed mapping functions that define routes and executable code or references, rather than using Controllers like in MVC. Even the WebApplication
class CreateBuilder()
and builder.Build()
functions are single-lineContinuing MAUI training, nearly done!
Key Takeaways:
SQLiteAsyncConnection
field, calls init (only if connection is null), has a constructor that accepts the connection string as a string, and has basic Table operations such as Add, Update, GetAll, etc.App.xaml.cs
) so it is available while the app is running.Task
type, not a void (Task can be null).I completed the learning path and acheived the trophy "Build mobile and desktop apps with .NET MAUI"! This adds to my collection of Achievements from a couple years ago:
The Azure DevOps Learning Path was only a single module? Maybe they've been updating modules and that one was legacy. Whatever, moving on.
The weekend was busy, mostly with other tasks and committments. I'm back on the MAUI training path again.
After completing several .NET MAUI modules, I'm learning my code style usually over-codes, and under-utilizes built-in framework capabilities for things like making REST calls to an API. A few of the concepts are relatively new like Connectivity.Current.NetworkAccess
and the NetworkAccess
enumeration, other Classes and Properties of System.Net.Http
are not new, and I have failed to make the best use of them.
Key takeaways (so far):
While working through more MAUI modules, a wonderful discovery is the DynamicResource
Type, and the ability to edit K-V pairs in it at Run Time. Just use C# code to index into the dynamic resource collection and set each KVP accordingly, then update the XAML to use "{DynamicResource DynResName}"
for the references that need a dynamically set value!
<!-- portions of this code are from MSFT Learn MAUI Modules -->
<ContentPage ...>
<ContentPage.Resources>
<Color x:Key="fgColor">#0000AD</Color>
</ContentPage.Resources>
<Grid ...>
<Label TextColor="{DynamicResource fgColor}" FontSize="{StaticResource fontSize}">My Label</Label>
<!-- more XAML Controls here -->
</Grid>
</ContentPage>
...and...
public partial Class MyAppClass
{
// CTOR etc here
// handler for the Light button
void OnLight(object sender, EventArgs e)
{
Resources["fgColor"] = colorNavy;
Resources["bgColor"] = colorSilver;
}
// handler for the Dark button
void OnDark(object sender, EventArgs e)
{
Resources["fgColor"] = colorSilver;
Resources["bgColor"] = colorNavy;
}
}
Completed more MAUI modules, creating Apps for Windows and Android. There is a bunch of borrowed syntax from WPF XAML that converting most of my development experience to MAUI should be fairly straightforward. There are a few changes in some of the syntax due to the extra layer MAUI adds over all 4 supported platforms, but those changes (so far) aren't too difficult to understand. Thinking ahead, even if the Bib Sync Tool doesn't get ported to MAUI (right away or ever), I have at least two backlogged mobile/Android projects I want to work on someday, and MAUI might be a good path to getting those want-to-dos done.
Completed MAUI modules, creating Apps for Windows and Android. Documented learnings in a new conted file. Most of the MSFT Learn module notes are moved to this new file from the 'mobile-to-desktop' one referenced yesterday.
Catching up from yesterday:
Completed implementing hover actions over custom 'pill' shaped and round buttons used in the file sync project. In the time it took me to sort all of this out, I could have written 3 full websites with React and CSS (maybe 4 using Bootstrap ). The reasons are:
For now, I think I have the basic gist of how XAML UI customization is done, but it will be some time before I know what I am doing. In the meantime, the project is practically at MVP!
Next steps:
One additional thing I am proud of in this project is implementing accessibility features. ToolTips were added to buttons and textboxes, and a color palette that maintains high contrast for users with any of the 3 types of color-blindness that 1-in-10 adults experience to some degree. These often overlooked design considerations are not difficult to implement when using resources to help implement them, and enables additional users to utilize the software.
After much consternation, I have a pill-shaped button with custom colors and responsive design that changes the button design between normal, hovered, and clicked. I still need to settle on color scheme and also add the disabled state design. At least now the basic template for how state changes are achieved is worked out.
An interesting and helpful Style property, BasedOn
, allows application of merged Style resources to a target type. For example:
<Style x:Key="DefaultPillStyling"
TargetType="{x:Type Button}">
<Setter Property="..." Value="..." /> <!-- etc -->
</Style>
<Style x:Key="ButtonPillStyle"
TargetType="Button"
BasedOn="{StaticResource DefaultPillStyling}">
<Setter Property="..." Value="..." /> <!-- etc -->
</Style>
The applies Style settings from both configurations, allowing some buttons to apply just the DefaultPillStyling, and others to apply that and more.
Lots of studying and working with XAML templating. Blend helps out a bit in getting lots of configuration set on Controls, and even has a state management toolbar. Some takeaways:
Border
) can have a VisualStateManager
attached to it so that visual states like Normal
, MouseOver
, Pressed
can have custom colors or other properties like BorderThickness
.VisualStateManager
enables setting Storyboard
instances where ObjectAnimationUsingKeyFrames
can be configured. This gets a little complex IMHO but a well-formed configuration (by Blend ) is not too difficult to read through and get an idea of what it is doing.Style
can be configured as a key with a TargetType
that points to a Control like Button
.Style
element, Setters
are used to set properties like Width
.Template
Setter Property has a Setter.Value
property that a ControlTemplate
can be configured within for a specifc TargetType
(like Button
).Color
and SolidColorBrush
are not the same Types, nor are they Polymorphic to one another. Some Properties require a Color
to set it, others take a SolidColorBrush
.<SolidColorBrush Color="{StaticResource ControlMouseOverColor}" />
(a Color, not a SolidColorBrush), and <Setter Property="Foreground" Value="{StaticResource PrimaryBlackBrush}" />
(a SolidColorBrush, not a Color).Many of the items learned yesterday were implemented today in the File Sync Tool. The tool is getting close to ready, but a few tasks still need to be completed:
Some other takeaways using Caliburn.Micro and customizing buttons:
Can
as a Getter in a ViewModel will break the Button Click handling functionality of Caliburn.Micro. This makes sense since the Can
prefix is meant to control the enabled state of controls, not manage the action taken when the control event occurs.And I though CSS was challenging. Customizing screen elements and applying style to WPF Apps using XAML is a bit of a bear. Somem key takeaways:
ResourceDictionary
XAML classes to define often used Color
and SolidColorBrush
settings.ResourceDictionary
to a ResourceDictionary.MergedDictionaries
element so they can be looked up behind the scenes.Application.Resources
like ResourceDictionary
through use of {StaticResource ...}
properties.Background="Transparent
and WindowStyle="None"
. This will get the App out of "Windows 95 mode".
Background="Transparent"
, that sets the entire Window background, so it is a good idea to have an image to display in place of the now transparent Window. Otherwise, your Window Controls can get lost in the now amongst any Desktop images, icons, or other Windows that might be behind your App.This work will continue into Sunday.
Working with .NET and C# the last few days, specifically my Coordinate Conversion Utility, I learned a few things:
I've been reading up on a bunch of different topics, but the only one worth mentioning here is the Liskov Substitution Principle. Tim Corey of "IAmTimCorey" fame states "this is the L in SOLID". At a very high level, the principle states that substituting inherited types should not break the application. For example, inheritors should not make changes to an inherited class when using polymorphism. The way Tim Corey explains how to work around it is to extract Interfaces from the most parent class, and create an abstract base class that implements that interface, from which other classes can inherit. Those inheritors should then have Interfaces that describe the differing behavior (from the Base Class) to more strongly define their specific sub-types -- the "extra stuff". Also, functionality should require Interface Types (rather than concrete types) to ensure only those types that should use that functionality actually can. Doing all of this just ensures that all child classes are indeed "IS A" base class. A nice benefit of following the Liskov Substitution Principle carefully is the Compiler will catch coding errors at compile time, rather than runtime (harder to debug).
Key takeaways:
Ask Yourself:
In terms of derived types:
See Covariance and contravariance in generics at Microsoft Learn.
Related vocabulary:
Object
The final big tests of the sync tool were yesterday and today, and after a good deal of troubleshooting and researching, the tool is now able to transfer data across a WiFi network between computers without errors. My lack of familiarity with the HTTP-based modules, especially Dot NET 6 and ASP.NET Core, made for a big challenge. The basic setup is a client computer wants to POST some data to another computer on the network, on a specific port. Besides the obvious requirement of "the server must be listening", there are several other requirements.
Here is a list of takeaways from ASP.NET and POSTing REST calls across a network:
UseHttpsRedirection()
tells the web server host to reply to the caller with a redirect when an HTTP path is used, so the caller knows they must send TLS-based traffic on on the reply. There are probably some additional coding steps needed on the callers' side to handle those redirects properly (something I have yet to figure out). For this MVP app, using unsecure HTTP is fine (there is no data worth hiding anywhere in the pipeline) so this feature is shut off.Program.cs
in the WebApplication.CreateBuilder
method, and using appsettings.json
kestrel settings. In my experience, the former way of configuring Kestrel allowed accessing the service from another host on the network, although more reading and understanding is needed on my part to know how and when to leverage each.Example Code Drilling into an InnerException:
public async Task<Tuple<bool, string>> PostStuff(MyModel model) {
// some code...
try
{
using (HttpResponseMessage response = await _apiHelper.ApiClient.PostAsync(requestUri, httpContent))
{
if (response.IsSuccessStatusCode)
{
result = true;
message = "Succeeded.";
}
}
}
catch (ArgumentNullException ArgNullEx)
{
message = $"Argument Null Exception Stacktrace: {ArgNullEx.StackTrace} Message: {ArgNullEx.Message}";
if (ArgNullEx.InnerException != null)
{
// tack-on any child message.
message += $"\nInner Exception Message: {ArgNullEx.InnerException.Message}";
}
}
// other Exception catch blocks here...
return result;
}
Example Host Firewall Allowances:
Name,Group,Profile,Enabled,Action,Program,LocalAddr,RemoteAddr,Proto,LocalPort,RemotePort
filesyncapi.exe,public,yes,allow,{filepath},Any,Any,TCP,Any,Any
filesyncapi.exe,public,yes,allow,{filepath},Any,Any,UDP,Any,Any
Attended a MSFT Reactor session on .NET MAUI Handlers and Native Controls. After looking at the MAUI repo and Microsoft Learn pages about MAUI, it is still in its infancy, but there is a lot of activity and documentation supporting development. One key drawback on developing MAUI apps is developing iOS native requires 'a networked Mac' (presumedly to run Mac Catalyst). I've missed some sessions in the series so I intend to catch up on those.
I tested using the Client-side sync tool while a live Winlink Express app was creating and receiving messages. The file accessing operations don't seem to interfere with each other. This was an important test and a good win!
"When coding becomes difficult, it might be because the coder isn't following best practices." -Me
I've found several areas where I wasn't following good coding practice, and the code was becoming tough to read and too complex. After some refactoring, moving classes around and simplifying various methods by breaking them out into multiple functions, it became easier to read, edit, debug, and add-on to.
Ran a few experiments with AREDN Mesh over the weekend into today:
I was beginning to believe Caliburn.Micro may never get updated to support Dot NET MAUI, then I ran into Ken Tucker's Blog. He includes instructions on how to setup Caliburn.Micro and use it in your MAUI workload. Ken also has a repo named ClientNoSqlDB that might be interesting for my current synchronizing project, so I'll take a peek at that soon.
Was tough to get a working solution to implementing a structured logging interface like Serilog. Code-wise it is fairly simple, but dependency-wise there are issues. Also, there are upgrade-related issues in Caliburn.Micro that a project upgrade to NET 6 will bring about. So for now I'm stuck with Dot NET 4 WPF project, unless I move away from Caliburn.Micro, or wait for v5.0.0 to be released (which there is no published date, just a 12-word roadmap).
Key takeaways:
The project is at a point where the primary features are working in a development environment. The next planned steps, roughly in order:
By the end of the day the Desktop and the Web Service are functioning as expected and are stable. I took a look at notes I'd been taking on paper and realized there is a lot more yet to do just to get to MVP. However, some sorting through all of these items has allowed my to prioritize them, and decide what really needs to be done, versus what can wait (or not be done at all if the end users don't need it). So I set up a Trello board to track everything so I can stay on top of it. There are plenty more ideas for this project, so a backlog column was added to capture my ideas, as well as those from end users, once they are engaged as I close-in on MVP.
Microsoft's WPF has an interesting feature: DispatcherUnhandledException
class. Basically, in the startup App class 'App.xaml', an event handler can be bound to any raised DispatcherUnhandledException
Type. The event handler (in code-behind file 'App.xaml.cs') is like any other handler in Dot NET: private void OnDispatcherUnhandledException(caller object, DispatcherUnahndledExceptionEventArgs e) {...}
where error handling implementation is expected. After reviewing Application.DispatcherUnchandledExceptionEvent documentation, it is clear there are some requirements:
Application
class.For Exception-type events that occur on threads with their own Dispatcher (or no Dispatcher at all):
Caliburn.Micro has a virtual method OnUnhandledException(object, DispatcherUnhandledExceptionEventArgs)
that can be overridden and used to call a custom handler. One way to handle this is to show a MessageBox with information for the user (if that makes sense to do). Another would be to log the event somewhere (especially if the user couldn't do anything about it anyway).
While looking up best practices converting custom types, I ran into this ASP.NET Core Best Practices for DotNET 7. There are several items in the list that could apply to my current pet project, once it is out of MVP and growing.
Completed bug squashing and updating the README for the current version of the sync tool. One thing occurred to me: I'd forgotten how to build and deploy apps from Visual Studio.
Key takeaways:
Check out ASP.NET Core 6.0 Fundamentals for more details on Publishing an ASP.NET project.
My custom logging is a little messy, and probably too verbose. While it is true the logging can be turned on or off, the way I am going about it is not how it is done using Dot NET assemblies. So I took a look at Microsoft.Extensions.Configuration, Microsoft.Extensions.DependencyInjection (for review), Microsoft.Extensions.Hosting, and Serilog. Next step is to try and refactor the logging within the Projects so I have better control over what is logged and when. For example, while debugging and developing, lots of logging can be a good thing. However, a released product should avoid producing a ton of logs (be default).
Back to work on the file sync tool:
POST
execution to push valid bib data to the 'server-side'.ActivateItem(IoC.Get<TService>())
. Wouldn't hurt to verify the Bootstrapper Container is configured to look for valid ViewModels, too.<appSettings>
for any runtime-configured items.T?
is necessary and null-checking the nullable reference type will cause warnings in the Error List. Generally speaking, with smaller DotNET Framework 4 Console and Desktop projects, it was fairly easy to avoid an unexpected null reference situation. It makes sense to be explicit about it, so as to avoid the less obvious failures that could occur.Configure()
method calling base.Configure()
at the end. Looking at the definition, the method is empty and only exists to be overridden, so going forward it doesn't make sense to have that 'base' call within the method.As it stands now, the application is able to successfully:
{bib_number}\t{action}\t{24hr_time}\t{day_of_month}\t{2_char_location}
.The feature set is nearly complete, so the project is well on its way to MVP. The following work must still be completed:
Completed a 2-node network at home using the following equipment:
For now all devices but the VLAN Switch are powered by 120v PoE injection. These will eventually by powered by a battery instead, via a buck-boost device, or a small inverter. A second 'site' will require its own power source(s), and as I get closer to goal #3, this will get addressed.
Back to coding!
Some key takeaways:
TService
. If using a custom class that inherits an existing interface such as ICollection
, it is not a good idea to use that as the TService
for containerizing the Singleton. For example, identifying TService
as ICollection
caused the Singleton to instantiate a bare Collection that did not support my custom collection type as expected. Using IMyCustomCollection
that inherits ICollection worked as expected.System.IO.FileSystemWatcher
needs to be configured to call an event handler like OnCreated(object caller, FileSystemEventArgs e)
, and have EnableRaisingEvents
field set to 'true' else it won't work as expected.OnCreated
handler does not have to be a static method, as indicated in the FileSystemWatcher docs. I think the example was written that way because it is instantiating the watcher within static void Main()
(silly). Using a non-static event handler works just fine, and simplifies further processing when the handler is called.On Saturday I attended an AREDN Mesh workshop and learned how to load AREDN firmware into some cheap 2 GHz and 5 GHz routers and APs (AREDN stands for Amateur Radio Emergency Data Network, and is a non-profit organization of volunteer software developers). It has been a bit since I last had to do any serious networking, and I managed to get firmware loaded on two of the devices - a TPLink CPE-210 and a MikroTik hAP Lite. I had purchased three devices including a GL-iNet AR300M for use with AREDN, but have since decided that hte GL-AR300M is better utilized as an access-point/repeater with built-in firewall for use in hotels, coffee shops. It could be used as an AP for a local WiFi LAN for AREDN too, but many of the AREDN devices are setup as 2 GHz 'mesh' radios with 5 GHz 'WiFi' (LAN) radios, so the AR300 is banded for the MESH, rather than the end-device network.
My Goals Working With AREDN:
What I learned today: When I start loading a class constructor with lots of logic...
public class DataProcessor {
private SomeHelperClass someHelperClass = new SomeHelperClass();
public DataProcessor(string[] someComplexData) {
_logger = new Logger();
foreach(var dataItem in someComplexData) {
do {
// process the data here
}
}
}
}
...what I should really do is refactor the solution to include a helper class that will do the heavy lifting and employ Inversion of Control (IoC or Dependency Injection) so the class is always ready, either as a Singleton or as a Dynamically instantiated dependency:
using Caliburn.Micro; // for example
// more usings...
namespace MyNamespace {
public class Bootstrapper : BootstrapperBase {
private SimpleContainer _conatainer = new SimpleContainer();
public Bootstrapper() {
Initialize();
}
protected override void Configure() {
_container.Instance(_container);
_conatiner
// various .Singleton<>() entries...
.Singleton<IDataProcessorHelper, DataProcessorHelper>();
// foreach to find ViewModels using Reflection, for example
}
// other Caliburn.Micro DI-related methods here
}
}
public class DataProcessor {
private IDataProcessorHelper _dataProcessorHelper;
public DataProcessor(IDataProcessorHelper dataProcessorHelper) {
_dataProcessorHelper = dataProcessorHelper;
}
public bool ProcessData(stringp[ someComplexData]) {
do {
// process the data here using _dataProcessorHelper methods
}
}
}
It is safer and cleaner to stictly initialize an object instance within a CTOR, and not introduce lots of processing. What if something goes wrong? Try-Catch won't help you within a Constructor (the instance won't get initialized properly). With DI, all requirements to instantiate an object are handled ahead of time, so the instance is ready to respond to Method calls.
See more at the Caliburn Micro home page.
Revamped the Project layout in the file-sync-win Solution so that it is better arranged for building future features and will be easier to test and debug.
Completed a few exercises on using MVVM in WPF. Seems like Caliburn.Micro is a great way to go so I'll give that a spin. I'll want to reorganize the files (some more) to support Inversion of Control (Dependency Injection), but after some research it might make more sense to get Caliburn.Micro installed and functional first, then take on DI if it will still be helpful.
After some work refactoring and adding Caliburn.Micro, I have the main UI functioning again. Takeaways:
Can
prefixed Property for the Action that can en/disable the action based on state.NotifyOfPropertyChanged()
must point to the Can
-prefixed Property so it "knows" the state has changed.csproj
files track it, so do the Class cs
files, as well as the xaml
files in XML-style namespace definitions. Visual Studio doesn't help much when there is a bad Namespace entry, and the error message might be pointing to the wrong problem source, so tread carefully.Struggled a bit with getting starting features up and running with this WPF app. Some notes:
StartupUri
that takes a string, pointing to another file in the Project. Putting code-behind at App.xaml doesn't appear to have any effect when this property is set.Loaded
and Closing
properties set, which allow WPF to call specific code-behind methods. This is optional but can be useful to help bring-up or tear-down the WPF application when the Window
opens or closes.However, I was able to implement some good practices without too much heartache:
TODO Items:
Completed a first-pass of a client-server solution that copies specific file data from a client (or at the server) into a MongoDB document store. The idea is to help solve the problem of copying 'bib data' from multiple Winlink Express workstations to a central "database server" workstation without having to manually sneaker-net or Telnet the files to the "server" computer. This exercise proved-out some design possibilities, some problems with my initial approach, and will help drive a better overall design for a possible future solution.
Began working on a possible WPF based solution for this file synchronizing utility. It is nice working with C# again, but I don't miss XAML. Why can't I just use CSS?
It's been a super busy week, followed by a couple days of travel mixed with some relaxation. Now it's back to work time.
Some Key Takeaways for the day:
Attended a MSFT DotNET MAUI presentation: Databinding in MVVM. I've been away from C# for some time but recall working within an MVVM model to develop WPF applications. For DotNET MAUI it isn't too different, and there is now a toolkit developed by Microsoft to help implement the MVVM model. This was an informative introduction, and I look forward to working on a DotNET MAUI project in the future.
I have a new project idea, related to the Bigfoot Bib Report Form project, that will require some research and time to design. At the moment I believe Socket.IO to be a good candidate as the underlying infrastructure for the project:
Experimented with Watcher to utilize as a means to watch a file system for a specific file type. Once a file change is discovered, a separate module can be called to parse the file to capture the necessary data. This was a very early experiment, but there are a few takeaways:
package.json
(not difficult in itself, but its effects can be).import
statements in ESM? No? import express from 'express'
instead of const express = require('express')
.DotEnv
can be configured by using import 'dotenv/config'
instead of require('dotenv').config()
.These changes will take a bit of time to sink in to my grey matter.
Attended a MSFT Reactor session about DotNET MAUI. Key takeaways:
Recall NextJS Project setup steps:
npx create-next-app@latest myProjectName --use-npm
set-location -Path myProjectName
Not much to write about due to other tasks interspersed with working on the BF Winlink Form, and planning around some of my personal goals for the next few months.
Finished implementing the mock server basic functionality of:
next(err)
syntax.Fiddled with my mock WLE server code trying to get it to read a specific file, edit a specific string within the file, and sending the entire file with changes back to the requesting client.
Key Takeaways:
I've started writing custom scripts for Package.json in node-based projects. In today's case, I had to re-write a small section of an HTML file prior to the web-server loading it as a static page.
Key takeaways:
path
must be installed using the npm registry
.path.join()
accepts an array of strings as arguments to string-together a directory path OR a fully qualified directory path and filename (depends on which you will need).fs
is built-in to node.js and does not need to be installed.fs.readfile(path.join(...), 'utf8', (err, data) => {...});
to do the work.scripts
section of Package.json to create a scriptName key like "rewriteAction":
, with a value "node path/scriptName.js"
.npm run rewriteAction
and node will do the rest for you.I came up with an idea as to how to address the issue request 'copy most recent supplied entry' for the Bigfoot WL Form project. At first I thought I could get away with just using Local Storage and saving the data to a file, but I didn't quite implement it correctly. So I took another tact, trying to implement a forced save during Form Submit event, but I failed to block the default form action so the data would get lost instead of stored. I then realized that Local Storage will do the trick, however I need to block the default form action before setting the "last record" values into LS, then the form can close. The challenge will be setting the form items correctly into the multi-part form transfer that the Winlink Express 'server' will require. That's my goal for tomorrow.
Key takeaways:
Completed the rest of the JS challenge started yesterday. Miro was still being sluggish but I completed the challenge anyway. Take aways:
Do not use the built in 'replace()' function for your chosen language
was a requirement but I somehow failed to add that to the code comments.Finished up research and writing about Mocha, Jest, and Chai. Key takeaways:
Made some progress working through a new Issue raised by a Bigfoot ham: Allow storing and incrementing the Message Number.
Worked through several JS challenges in CodeWars and completed one in the style of a whiteboard interview: URL Spaces.
I reserached several companies with interesting open positions, none of them were in industries (or locations) that were exciting to me.
Worked through Jest.JS documentation and took notes for future reference.
I've been slowly working through Next.js getting started documentation. Some takeaways so far (what I think I'm learning):
getStaticProps()
to fetch data for request-time rendering.[
and ending with ]
, e.g. [id].js
.Sorted through a bunch of in-progress projects and those that are on the back-burner. I didn't remove any, but did some re-prioritization, and added a couple new ones. Then, while looking up how to package and publish code, I ran into Next.js documentation, which is something I'd wanted to look at for a while so I started a new project to learn how to use it. I'll get back to the build, bundle, package, and publish exercise later (if anything, this Next.js documentation has been helping understand the processes involved).
I also worked on some documentation for the Bigfoot Winlink form. I'll need to review the Readme and update instructions now that the form is in a good state. Mostly importantly, the instructions on how to share files between Windows and Android devices needs to be added. Some of that documentation took some time to look up and validate, but it will be really helpful for users.
Updated my Portfolio WebApp with the Bigfoot Form project at version 1.0.6. There are some issues I need to resolve with the Portfolio WebApp when I get a chance:
One of my backlog items is to learn how to build, bundle, package, and publish a project. For this exercise I will use React as a starting point.
Continued working with Chai and learning how to integrated it into the JS-code-challenges repo and test the code challenge from yesterday. Some key takeaways:
const assert = require('chai').assert;
and then the assert
object is used to make assertions like assert.typeOf('', 'string');
.const expect = require('chai').expect;
and then expect
is used to make assertions like expect('').to.be.a('string');
.const should = require('chai).should();
, including the ()
at the end. Then should
is used to make assertions like ' '.should.be.a('string');
.strictly equals operator
: const in='me', out='me'; assert.isTrue(in !== out);
.On the Bigfoot Form front, enough time has passed since advertising changes without hearing of any problems that I went ahead and closed issues and merged-in fixes and enhancements. The first volunteer meeting is coming up on Monday, where I anticipate having a moment to talk about the form, how it is working, and provide general guidance on using Winlink for Bigfoot.
I completed a code challenge that required parsing through a string of alphanumerics and spaces. The idea was to reverse the case of the alpha characters such that Upper Case letters would become Lower Case, and vice versa. Non-alpha characters would not be affected. One rule was to keep the function pure, and to develop it as a prototype (in JavaScript) e.g. String.prototype.toAlternateCase()
. Takeaways:
String.split("");
is effective does not mean it is the right way to go. This will force the code to process string items in an array regardless if they are alpha or not.String.match(/\d|\W/g)
can be effective but it is not always necessary if it is a 'default case'.String.replace()
would not work because that would mutate the input.String.at()
to iterate through the characters of a string without having to deal with an array.String.at(idx)
character is uppercase or lowercase is all that is necessary for Strings.String.toUpperCase()
(or lower) is an 'all are welcome' operation and will not fail if the character is not alpha.Testing with Chai:
npm test
probably because it is driven by Jest framework.toAlternatingCase()
, so I'll need to work out how to get that prototype function to be available to the test.Here are some key takeaways from reading about Java Stream Collectors:
@Override
annotation is used to indicate the method is overriding an Interface-defined member.Arrays.asList(...)
to rapidly create a List<T>
from a comma-separated list of items. This is helpful in testing or when managing custom inputs from a user or process.Function<T, U>
Interface represents a function that takes an argument of type T
and returns a result of type U
. When this is used, the output type of the function is determined by the return type of the apply
method.Overall I am feeling a bit more comfortable with Java Streams API. I will need to practice more to get a better feel for the syntax and how to use it effectively.
I've been reviewing the Chai Assertion Library the last few days:
In a future JS project I will try using Chai for assertions.
Completed a code challenge in Java. Two things I'd forgotten about:
Did some self-study of JavaScript frameworks. Notes are linked from the Conted Index page.
Cleaned up documentation references in this repo - there were a few floating documents with no links to them so they were difficult to find.
Updated Azure-Deploy YAML in LingoBingo API server repository (only on the azure-deploy branch). My notes on GitHub Actions: Build and Test Node.js App has details.
My Portfolio React SPA has several dependencies that have moderate vulnerabilities and/or are no longer supported (deprecated). I've removed a few of the dependencies that weren't needed, updated others to the latest version, and set a plan to replace the Vertical Timeline component sometime in the future.
Updated my Create-Markdown-TOC VSCode extension to version 0.2.1 with bug fixes and an enhancement (based on the bug fix). The Visual Studio Marketplace page has some metrics on downloads and page views that might be worth watching as I continue to develop the extension. The automatic update was seamless and I verified functionality on a few files locally.
Takeaways:
vsce publish
to package and publish the correct version to the marketplace.Learned something about CSS, by accident, while looking at a fun project at github.com/jdan/98.css:
<hr />
by default appears as a single line across the width of it parent container.<hr />
be set, but also the height. This effectively makes a box outline.<hr />
element./* just showing some styling possibilities */
hr {
height: 0.5rem;
width: 90%;
text-decoration: none;
border-top: 1px dashed rgb(0, 0, 0);
border-bottom: 2px solid rgb(255, 0, 0);
border-left: none;
border-right: none;
}
Last night I finished implementing some fixes to my create-markdown-toc VS Code Extension. The bug was related to how the extension handled unsupported characters in link fragments. The result of the bug was a linter warning that (in most cases) would be easy to fix by hand. Since the extension creates the entries that should be legitimate but aren't, it's a bug. The solution uses string.replaceAll(/regex/)
to find a list of unwanted characters from the captured heading's "title text", and replace them with nothing (remove them). The result is a link fragment that is more likely to work as expected. I added unit tests to support the new code and am working on some manual-test scenarios to further test the code before publishing the update to the VS Code Marketplace.
GitHub Copilot has been helpful. I've learned how to prompt it to generate better suggestions. Microsoft Build had a session discussing how to leverage GitHub Copilot, and it turns out I was using some of those techniques already.
Refined a bug description in project markdown-toc: This markdown file contains L2 headings that include a dash -
character in the name. My code generates fragmented links for these headings. An Issue is already in the project and is capturing problem experiences so that I can generate a list of test cases to use when I get to fixing the bug.
I worked through a new code challenge and learned a few things, and then updated code and tests to a previous challenge due to lack of code coverage that I hadn't noticed before:
if (thisSubArr != 0) {...}
instead of if (thisSubArr < 9) {...}
..editorconfig
works to enforce linting on the encompassing project, and can target specific files and file types. Updating this in the js-code-challenges
simplifies execution of Prettier without having to battle with VS Code settings or ESLint
settings.yaml
workflow asks to lint files on merge or push, I still have to retain the .eslintrc.json
but I could simplify it a bit by removing items that the .editorconfig
file will handle. Perhaps this is still duplicating effort? I'll figure that out some time..size
property (like Java), and Arrays have a .length
property.package.json
file was targeting dependencies that were out of date. I removed the existing node_modules
folder, then uninstalled and reinstalled the dependencies to ensure they would be to the latest versions.package.json
has a schema (of course) that I'd never looked at before. Today I did and learned that I should be using a few settings like private
and repository {type, url}
. Also, there is not only an author
(a person) but also contributors
(collection of people). name
, email
, and url
are Person properties that I should be including.chai
and it wasn't too difficult. There is some syntax that I would need to learn (or get used to looking up) that make it different than Jest, but overall is a viable option. I'm not sure what the benefit of using one over another is, but I'll figure it out some day.// fast fail if any zeroes are detected or if size of a row is not equal to 9
if (rowMap.size != 9 || rowMap.has(0)) {
return false;
}
// later on...
if (thisCol.size < 9) {
// not as precise as the previous if statement and is never true if the previous is true
return false;
}
Posted an update to LinkedIn about completion of my VS Code extension create-markdown-toc. I added a short description and a few in-action screen shots. As I complete other projects I look forward to doing the same.
Looking at an older team project - EZ-PC-Shopper:
Some code snippets I developed these last few days working on the Winlink Form project:
<input type='text' class='readOnlyText' readonly />
to be different than regular (read + write) text inputs, providing a hint of alternate functionality. A user can still select and copy the generated text from the readonly text input without accidentally editing or deleting it.<div>
elements in conjunction with CSS to help move elements around when the viewport size changes. This may seem like simple stuff to experienced JS developers, but it is a big win for me.Media queries to control font size and element size:
@media screen and (width < 650px) {
label,
input,
textarea,
select,
button {
font-size: 0.7em;
}
input {
margin: 0.2em 0.2em;
}
input[type='checkbox'] {
width: 1em;
height: 1em;
}
.formTitleHeader {
font-size: 2em;
}
.msgHeaderTitle {
font-size: 0.7em;
}
.addressInput {
min-width: 70%;
}
}
@media screen and (width >= 650px) {
label,
input,
textarea,
select,
button {
font-size: 1em;
}
input {
margin: 0.3em 0.3em;
}
input[type='checkbox'] {
width: 1.2em;
height: 1.2em;
}
.formTitleHeader {
font-size: 3em;
}
.msgHeaderTitle {
font-size: 1.1em;
}
.addressInput {
max-width: 55%;
}
}
Centering elements without using flexbox or float:
.div-across-auto-align {
width: 100%;
margin: auto;
text-align: center;
}
Read only text input field decoration:
.readOnlyText {
color: rgb(84, 84, 84) !important;
outline: none !important;
cursor: default !important;
opacity: unset !important;
}
Items that are hovered over change the cursor, opacity, and border style for visual feedback:
input {
padding: 0.2em 0.2em;
border-radius: 0.5rem;
}
textarea,
select {
padding: 0.3em 0.3em;
border: rgb(0, 0, 0) solid 0.15em;
border-radius: 0.5rem;
}
input:hover,
textarea:hover,
select:hover {
cursor: pointer;
opacity: 0.8;
}
An active element (clicked or tabbed-in to) border style changes for visual feedback:
input {
padding: 0.2em 0.2em;
border-radius: 0.5rem;
}
textarea,
select {
padding: 0.3em 0.3em;
border: rgb(0, 0, 0) solid 0.15em;
border-radius: 0.5rem;
}
input:focus,
textarea:focus,
select:focus {
outline: rgb(255, 153, 0) solid 3px;
}
Simple local storage API usage:
// store Form element values into localStorage
function storeElementValueToLocalStorage() {
var addressFormatted = document.getElementById('address');
localStorage.setItem('addressKey', addressFormatted.value);
}
// load values from localStorage and populate elements in a Form
function loadValueFromLocalStorage() {
const storedAddress = localStorage.getItem('addressKey');
if (document.getElementById('address').value == '' && storedAddress != '') {
document.getElementById('address').value = storedAddress;
}
}
Use of JSON Stringify to store multiple values into a single element value:
// this is useful for storing values destined
// for localStorage or for saving to a file
function captureValuesToHiddenElement() {
// call this function prior to saving data to a file
const address = document.getElementById('address').value;
const Location = document.getElementById('location').value;
const message = document.getElementById('message').value;
const formObject = JSON.stringify({
address,
location,
message,
});
// when the saveToFile function is called it will save
// the values stored in hiddenData element to a file
document.getElementById('hiddenData').value = formObject;
}
There is plenty more work to do with this project, but that will wait until after some of the intended users have a chance to use the latest update and provide some feedback.
Continued efforts with the Winlink Form have paid off. The form now features:
for
attributes to improve accessibility (Lighthouse Score: 100).One note about responsive design: I tried to keep all API usages compatible all the way back to Windows 7-era browsers, but have not tested outside of Chrome, Edge, and Firefox, so there is a possibility that Opera, Safari, or phone-based browsers won't see the benefits of these efforts. This is a low-risk situation because Winlink Express requires Windows 7 and newer, and most smart phones support Chrome or Firefox at a reasonable API level. I'm not sure about Opera or Safari, I guess I'll find out one way or another.
Major wins this week:
Diagramming software is pretty fun, and very helpful. Looking at the functions listed in the Bigfoot Winlink Form, it is hard to trace the paths and where the paths split, and which functions return anything, or affect the UI in some way. The diagram documented the following key components:
I discovered several things while developing the diagram:
Exploring use of FileReader, setting element values, and saving/loading data to/from localStorage.
selected
property on that indexed option attribute to true
.textarea
element, but in the case of the Bigfoot Winlink form, it is better to not maintain the location suffix with the rest of the bib records and instead just append that data when writing back to the server.I have some work to do to figure out how to get that last bullet point solved. Although it seems simple, the challenge is going to be how to solve it on the existing form without undesireable, unanticipated side effects. This could take a few days to solve completely, but I feel like I'm getting close to a solution.
Continued efforts cleaning up the Bigfoot Winlink form:
Working with the Home Sales Tracker Example app, in an attempt to get video and screen shots of it in operation, I ran into some bugs:
Happy Summer Solstice!
In an effort to add more completed projects to my portfolio, I started working on upgrading Home Sales Tracker App (from 2019 - 2021) from DotNET Framework 4.7 to DotNET 6. Here are some takeaways:
appsettings.json
, in place of App.config
files.There could be some errors along the way:
The following will cause an error when building a WPF project:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
</Project>
The solution is to target DotNET 6 using -windows
as a suffix:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
</PropertyGroup>
</Project>
I made some other notes in dotnetconf-2022 with some added reference links.
Also GH Copilot Extension exists for VS 2022! Will have to investigate other Extensions as well.
Updated my Portfolio project today and started to figure out how a few more code blocks work.
DevIcons in React - options:
class='deficon-vscode-plain colored'
.@import url('https://cdn.jsdelivr.net/gh/devicons/devicon@v2.15.1/devicon.min.css');
which enables settings the 'class' attribute with multiple values like 'colored'.It occurred to me that one of the issues with the Bigfoot Winlink Form is it is not obvious which element is currently selected, especially while 'tabbing around' the form. A solution could be to apply a 'box-shadow' to the element types that need to be highlighted when they have focus.
input:focus {
background-color: rgba(200, 200, 200, 0.2);
box-shadow: 2px 2px 10px rgba(16, 194, 45, 0.7), -2px -2px 10px rgba(16, 194, 45, 0.7);
}
Other input types can be targeted with this pseudo-class, including select:focus
, text:focus
, and textarea:focus
. The downside is the solution is 'heavy handed' in that every single element targeted gets this background-color and box-shadow. Another approach is to leverage onfocus
and onblur
events on the specific elements themselves:
<input
title="Send your responses to the survey."
class="submitButton"
enctype="multipart/form-data"
id="submit"
method="Post"
name="submit"
value="SUBMIT"
type="submit"
onfocus="style.boxShadow='2px 2px 10px rgba(16, 194, 45, 0.7), -2px -2px 10px rgba(16, 194, 45, 0.7)'"
onblur="style.boxShadow='0px 0px 0px rgba(0, 0, 0, 0.0), 0px 0px 0px rgba(0, 0, 0, 0.0)'"
/>
Webpage design learnings and takeaways:
event.keyCode
is deprecated: Instead, use event.code
and use Key_
where the underscore represents the key, for example: if (event.code == KeyL) { // returns true if key 'N' is pressed }
.window.onLoad()
method to make set calls on DOM elements.Webpage design thoughts:
VSCode API: The TextDocument interface lineAt()
function defines 2 overloads:
The TextLine interface defines lineNumber
(a Number primitive) but does not differentiate between what I would expect to be "Line Numbers" in a text document, and the zero-based numbering system for a structure like a Collection. So, when processing a TextDocument Type, be careful with handling line numbers to avoid unexpected results.
Took some time out this morning to help a fellow ham with some email-over-ham technology setup steps. He was close, and together we got the configuration squared away.
Worked on building out tests to increase code coverage to the remaining two functions in my VS Code Extension.
Lots of effort put into preparing for various upcoming events, including an all volunteer meeting tonight that included a presentation I was pegged to deliver on the agenda.
Completed a code challenge: Sum rows and columns from a 2D Array of Numbers. Key takeaways:
const arr = new Array(100).fill(0)
is an iterating structure and counts toward Big O calculations.const result = { rowSum: [], colSum: [], }
.Watched a presentation about Azure Bicep:
Worked through some preparatory work to get my VS Code Extension published. While I could have just published it the way it is, I decided to continue working on the last few unit tests to get better code coverage. Some key takeaways:
Was introduced to JSDoc this morning while listening to the Syntax Podcast. Historically I think I've done a pretty okay documenting my code. In some instances it hasn't happened until after the implementations (and maybe even testing) are completed. Turns out, my default mode of documenting seems to be compatible with JSDoc /** This function returns ~something~ */
so if/when I decide to use JSDoc it should be pretty simple getting going.
/**
* Find the first occurrence of a second level heading in the document.
* @returns Number The line number of the first 2nd Level Heading of the page.
* @param {vscode.TextEditor} editor The active text editor.
*/
module.exports = function findFirstSecondLevelHeading(editor, topHeading) { ... }
Key Takeaways Using Jest:
.toMatch()
and .not.toMatch()
, whereas Numbers are matched using toBe()
, toEqual()
, toBeCloseTo()
(etc).const rootDir = path.resolve(__dirname, '../../sut-functions');
and similar to help simplify traversing the directory tree.Have to remember that Linux and Windows "slash" characters are different. For example:
/
\
/
/
Fun.
VS Code Extension development status:
There are several more steps to take before publishing. It is getting close!
Focused on learning VSCode Extensions. I have a working idea for an MVP and am currently working on unit tests, documentation, and meeting VSCode Extension standards.
Caught up on VSCode happenings with an episode of VSCode Day from earlier this year. Appended some notes from this session to the github-copilot from a few weeks ago.
Started reading up on VSCode Extensions, and worked on developing an idea.
Completed a personal challenge: Update the Quicksort algorithm to accept any Number types, or other Types that implement Comparable<T>
. Final code can be found in java-code-challenges, Quicksort.java.
Spent 4 hours this morning at a volunteer event in Kenmore, which was a good experience overall. Beautiful day for an outdoor activity!
Researched WPF Controls and connected aspects, looking to find a solution to the Issue discussed yesterday. Not sure if my solution will meet the Issue (because the description is a little ambiguous), but I'll see how I feel after attempting to address it, and decide from there what to do.
Worked through a code challenge in JavaScript, sourced from CodeWars. Took about 2 hours to do everything except for actual code, and about an hour to implement code and unit tests, and perform debugging (majority of the debugging was of the unit tests, not the implemented code).
Took some time out to look at some MSFT open-source code (C#). It was interesting trying to piece together a large, multi-project solution I hadn't seen before. Drilling-down into a posted GitHub Issue in the project, I found the area that would need the fix, and started on a quest to re-learn the components that are necessary to adjust in order to address the Issue.
While working through Portfolio project tasks, I found the templated code used JavaScript 'var' to initialize a new variable. It was assigned within an if
statement code block, and was later used in the contianing function, appearing to be referenced before being declared. In C# and Java, var is used to limit the typing necessary to instantiate something that is otherwise obviously a specific Type. For example var newNode = new MyLLNode<Integer>(some_value);
. In JavaScript, var
is used to create and assign a variable that is scoped to the containing method (or globally if not in a nested function). This feature is allowed due to var hoisting
, which causes var declarations to be processed before other variables. The result is the variable is effectively assigned at the top of the function. MDN Var Statement. Next time I dive into that code I'll leverage this capability, and undo some of the code I added prior to understanding how to properly use the var statement.
Had a phone conversation with another software developer, Ken, about the C# language. Was great to meet him, geek out on programming languages, and share some empathy around the challenges of learning syntax, patterns, and frameworks.
Learned a little about integrating Chat GPT into applications, and some of the issues with securing an LLM Prompt.
Was able to finish configuring a Raspberry Pi security camera for watching the yard. There is some tweaking to do but it is ready for deployment, later today. The problem with focus was due to the manually adjustable lens. Simply turning it clockwise or counter-clockwise (slowly) adjusts the focal length.
Started refactoring the Portfolio project to better handle skills icons and simplifying code. My first attempt was changing too many ui and data elements, which broke rendering completely.
Lots of administrative stuff to do today, including volunteer-related emails, research, and preparations. The Ride Around Mt. Rainier in One Day (RAMROD) communcations team was looking for help so I signed up for that event, in the latter half of July.
Completed initial setup of a Raspberry Pi-based motion-sensing, streaming camera. It was a bit of a pain to set up, but I finally got it going. The video quality is quite low and appears to be completely out of focus. I'l have to do a bit more testing, with the camera set up to view items farther than just a few feet to confirm this is a known issue with some Pi Cams that set the focal distance to something less than infinite.
My Portfolio project React App was using something in SCSS called 'transparentize'. It was used to adjust the opaqueness of the background color of icons. Although it did the job I decided to change it to RGBA instead. Transparentize accepted hex values for color, and RGBA uses integers 0-254 for each color channel, and a decimal representing alpha from 0 to 1. I had not used these styling techniques before and they worked well.
Next time I decide to use DevIcons or Iconify, I need to use Iconify's search tool to get me started. Iconify has DevIcon sets within its massive store of icons, and the search tools has code in the search results for implementing in HTML, React, etc.
Deployed LBJS API using a YAML file! Assigned the task to a specific branch (not main) so that deployments would be managed with specific PRs. One issue is there are no tests yet, and that should really be part of the pipeline operations.
Completed implementing an Express server with Jest tests and GitHub Action that builds, tests, and deploys the server to Azure App Service. Next step is to apply what I've learned to LingoBingo API server so that tests can be implemented and deployment will be automatic.
Spent the day working on odds and ends.
Did some cleanup of my Bigfoot Bib Report Form repo, editing the README for clarity and to be up-to-date, removing an unused GH Action, updating the Packages to the latest version of HTML and TXT files, and deploying a preview site to Netlify of what an end user would see when launched within Winlink Express.
Completed the SQLBolt exercises to refresh my memory on using SQL Queries. Aside from all of the synax necessary to become proficient at CRUD, the exercises mentioned the order of operations within SQL Statements. In order they are:
Worked on a few issues with my Portfolio Website Project. Took a bit to warm-up to Bootstrap and in-line Styling. The major issue was alignment problems on the About page, and the minor issue was the About Me write-up. Both got attention and the webapp is now updated. Some things of note:
@iconify
is awesome! I utilized the imported iconify logos for now. In the future I'll want to try using the SVG files instead.map()
over the description props, assigning JSX to the output in the iterations, made the paragraph layout a little easier to read.Today is day 2 of Microsoft Build 2023. Key takeaways:
I started using GitHub Copilot today. Often enough I waste a good amount of time flailing around trying to produce just the right syntax, or looking up details on the internet to get to a sensible, effective implementation. I should instead be making better use of my coding time by minimizing time-to-learn and finishing managable tasks within a reasonable timeframe.
Seems like the best place to start is to resolve some existing issues in one of my exploratory code repos on my local laptop:
ListIterator<E>
instance. I removed the instance initializer and wrote a comments describing what was needed, just above the lines where the results were needed. Suggested code lines resolved the problem in devtime.Today is day 1 of Microsoft Build 2023. Key takeaways:
In between MSFT Build sessions, I worked on implementing AbstractSequentialList interface to a custom LinkedList class I recently created. Although the implementations aren't working yet, I learned a few things:
@Override public Iterator<E> iterator()
method without much trouble. It contains hasNext()
, next()
, and remove()
methods, and meets some interface implementation requirements. The rest of the requirements are hidden in ListIterator<E>
.hashMap()
function that is not guaranteed to produce unique hash codes (but is likely to due to sourcing hashmap from the memory location of the object) and can be relied on in most basic cases of needing a hashing function. Some cases will require overriding hashMap to include private field data that can uniquely identify an instance. This is not very different from C#.References for today:
Long volunteer weekend in Portland was fun, supporting the Multiple Sclerosis Society's Walk MS event. Great people, great cause.
Java Scanner class review key takeaways:
FileInputStream
.IOException
.scanner.close()
..close()
method closes the source too, which will affect other instances of Scanner.scanner.next()
..useDelimiter(string regex)
that works as expected. The default delimiter is an empty String. Multiple delimiters can be used in regex as a single string token.NoSuchElementException
.nextLine()
reads the entire line into a processable token.nextLine()
an additional time, or use scanner.skip("\r\n")
to force Scanner to move past New Line character(s).BufferedReader
to process lines from a file, instead of scanner.nextLine()
.new Scanner(System.in)
: Accepts a ByteArrayInputStream
(as an InputStream
)..next()
, .nextInt()
, and .nextDouble()
to identify tokens as those types natively. These are basically conversion methods with specific output types: string, int, and double, respectively..findInLine(string regex)
and the matched token will be returned. To search a wider scope use .findWithinHorizon(string regex, int count)
to define the domain/boundary of the search.Rummaging through Java Collections library I discovered a few handy things:
List.of()
in the constructor.NullPointerException
or false
when an element doesn't exist, versus returning null
in the same situation.Collection
for any collection types, and if the method accepts a parameter that could be an ArrayList<E>
or LinkedList<E>
, then set the parameter as a List<E>
Interface type.null
when a method returns a Collection Type (or Interface), instead return an empty collection.Using the List Interface Factory Method in a Constructor:
List<String> testLL = new LinkedList<>(List.of("alpha", "bravo", "charlie"));
As I experimented with Java based on inspiration from the above readings, I felt like I needed to review java collections and generics best practices. This led me back to some Java code examples I wrote while configuring VSCode for Java several weeks ago. Collections in Java include various types of Lists and Maps, and the supporting interfaces help drive functionality implementation and inherited capabilities. Turns out writing a custom LinkedList (or other collection type) class can be assisted by extending AbstractSequentialList
and other interfaces from the Java Collections library. I spent a few hours refactoring existing code into a Collections-extended, custom LinkedList class.
VS Code's twitter account linked to a VSCode YouTube Channel event featuring Dan Shiffman (@shiffman) discussing p5js usage in VSCode. It was inspiring and lots of fun.
Decided to create a DSA note taking page to track experiences and references so I can refer to those separately from the java-code-challenges or other repositories.
It's concerning to start the day opening an existing (last-known good/functioning) java project in VSCode and it logs errors on imports stating source cannot be found. Opening the Gradle Extension and clicking "Reload All Gradle Projects" solves the problem.
Working through Quicksort one last time. I was still confused about how exactly the algorithm does what it does, and would get stuck with certain test cases failing due to duplicates in the array, or ending up not-sorted or endlessly sorting. For those cases that ended up not-sorted/endless, stepping through the code in debug mode showed that the algorithm would sort the array, but the stop conditions were not correct to keep it sorted and the algorithm would then un-sort the array, putting it into a state that further recursive calls would never be able to sort because there would be out-of-scope values that are out of order.
Posh-Git:
$GitPromptSettings
properties. Open a quoted output with single quote '
, use double-quotes for inner quotations "
.Portfolio:
Code Challenge:
Added a GH Repo for a small project I started working on back in November. Updated the old default branch to 'main' (surprisingly easy). Added GH Actions to build and test, and enforce PR and Status checks prior to merging to main.
Got a little off-track setting up my local for more work with CoordinateConversionUtility and changed-up the Posh-Git prompt:
$GitPromptSettings
: Display all settings.$GitPromptSettings.DefaultPromptAbbreviatedHomeDirectory = $true
: Yay a tilde!PowerShell has its own prompt settings:
$(Get-Command Prompt)
Powershell 7.3.x Documentation
'$($(Get-PromptPath).Split("\")[-1])'
. Mmm, nested commands.JavaScript. So useful and at times so elusive. I completed a basic JS challenge within 45 minutes following the full CF rubrick, and the only hang-up was with validating JS built-in types. Key takeaways:
.NaN
which is unique to JS (arguably Python), and .MAX_VALUE
and .MIN_VALUE
, which are similar to Integer properties in Java.if (inputVar typeof === 'string'){...}
.if (inputVar.getClass() == Integer.class){...}
.if (inputVar instanceOf ParentClass){...}
. This is particularly useful when working with polymorphism.// multiline boolean return (simple example)
const bool1 = input1 % 2 === 0;
const bool2 = input2 % 2 === 0;
return bool1 !== boo2;
// single line boolean return from above example
return input1 % 2 !== input2 % 2;
Took a few side-trips:
Back to preparing Coordinate Conversion Utility for MPV demonstrating:
dotnet test
and dotnet test {path-to-unittest-csproj} --configuration release
both execute and pass.dotnet new console --framework net6.0 --use-program-main
and take a peek at .\vscode\launch.json
configurations[] and .\vscode\tasks.json
tasks[].Worked on some presentation materials for a volunteer meeting on Wednesday night. It's always a time sink but it forces me to organize my thoughts, and generate plans for the future of the organization, and for myself.
Worked through some reading and research on Java Streams API and functional interfaces.
Researched a potential employer (they don't appear to be hiring). Web-design consultancy in Seattle. Very small team, supports websites of at least one local event in my area. Turns out they use Wordpress site development, so my interest has waned somewhat. They have a good sales pitch describing who they are, what they do, and why. It was inspiring.
Worked on LingoBingo quite a bit, getting the code ready for cloud-hosted deployments. This is much more tricky than I anticipated:
.catch()
so there is no need to test for status codes.
useState
. For example, it might not be a good idea to update useState
with nulls and empty strings in an else
statement, otherwise that forces a refresh that really isn't necessary.It is pretty clear that one of my lacking skills is creative design in the UI. It's not that I don't want to be good at it. It could be argued that I am not that skilled at back-end development either, but the result isn't visual and so is not prone to immediate recognition of 'ugly' or 'not quite right'. Something for me to work on, and consider as I push forward in my developer journey.
Developing the back-end to be Azure AppService deploy and functional with Authorization and MongoDB CRUD took me about 4 months in all. Code was developed here and there as I learned new things and came up with new ideas. There were definitely times where no work was put into it. However IT IS NOW LIVE AT AN MVP LEVEL! Users can login (auto-register), create words and categories, and create gameboards that the React FE will consume and 'fetch' the correct set of words. There is more work to do though and the next step is to document what is done, demonstrate how it can be used, and debug it so it is stable and reliable. A little farther down the road additional features like Delete Word, Delete Gameboard, and Update (replace) Word will be implemented.
After some analysis of LingoBingo front-end and back-end environment variables and local vs. cloud configurations, the causes of the AuthN and AuthZ failures are now identified and my goal for the next few days is to get an MVP of the full-stack solution up and running in Netlify + Azure. Not much else to report other than lots of updating environment variables, editing code, squashing bugs, and deploying to Netlify and Azure again and again. Getting close, not there yet though.
There is a growing list of things that I want to do, and should do. These lists are forever getting larger despite the many things I do actually complete. The good news is part of the problem is there are a lot of things I want to learn about and explore. I need to remember that so long as I keep moving forward and achieve professional and personal goals, how big these lists are is less important than what I am doing overall.
Moved the LingoBingoJS FE & BE dev environment over to my Windows workstation. Took a little over an hour to get both FE and API Server up and running, connecting to a database, and authenticating via Auth0. This exercise (and helping Ryan get setup last weekend) informs me that I have a bit to learn about maintaining effective documentation during the development process.
Some key takeaways:
mongodb+srv://<username>:<password>@cluster0.0gxux.mongodb.net/?retryWrites=true&w=majority
. Be sure to edit this to point to a specific namespace such as LocalDevDocuments
e.g. mongodb+srv://<username>:<password>@cluster0.0gxux.mongodb.net/LocalDevDocuments?retryWrites=true&w=majority
to control where documents are stored and accessed. Configure this in the back-end .env
file before launching Node/Express..env.example
by taking an existing, working .env
file, copying it to .env.example
and then redacting actual values with explanations of what the value should be, and be specific.There are still plenty of issues to work through, but at least now I have a workable environment and can help move this last major portion of the environment forward.
Why did I wait so long to install MongoDB Compass? What was I waiting for? Compass is more capable than the Atlas website!
I started using VSCode.dev to write code in a web browser. While it is missing some functionality like Run-and-Debug and some Extensions support, it is practically the same as working in VSCode the application. Open the website, connect to a GitHub repo, create a new branch, write code, then use the Source Control widget to manage staging and commits. Simple, quick, and integrated. Good job MSFT and GitHub!
Watching Code Fellow students demo their 301 and 401 projects I learned a few things, and want to explore a few other things:
_redirects
file to manage Netlify route handling.// within the body of the React module:
const cardImage = {
width: '90%',
};
// and then within the render function:
<Card.Img style={cardIimage} src='' />;
// etc
Received some resume feedback. Will be using that to update my resume to be a little closer to stellar.
Worked on a few administrative tasks. Started building a presentation deck to review the commex completed last weekend. More to do, but it will be done in pieces.
Looking at my Portfolio webapp, it can use some help. I have run across at least one job posting that is asking for examples online, and this is a good way to aggregate the links to what I've accomplished. The Portfolio webapp is clearly missing a few projects, and some creative design elements. For projects, not a single Python project is listed, and the one DotNET project is pretty basic and does not highlight my experience with DotNET and automated testing. This prompted me to get a new project listed: Coordinate Converter. This was last updated 2 years ago using DotNET 5 (which is now out of support) so an upgrade was necessary. Also, the last time this project was edited I was using Visual Studio Community Edition. All of my development efforts have moved over to VS Code so there are some other updates that are needed.
Upgrading NET5 to NET6 Key Takeaways:
<TargetFramework></TargetFramework>
targets dotnet6
instead of dotnet5
.<ItemGroup>
elements in TEST CSPROJ files to include Micorosft NET Test SDK, MSTest Framework, and coverlet.collector (see below).using
statements: For MSTest this is using Microsoft.VisualStudio.TestTools.UnitTesting
.[TestClass]
instead of [TestFixture()]
, and [TestMethod]
instead of [Test()]
. <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.2" />
</ItemGroup>
In the future I want to:
While rewriting the readme, it became apparent there are more bugs in the code than I had anticipated. A few new Issues were added to the queue with these bugs, but I'm certain there are even more. The next time I pick up this project I need to build it and run it locally, fix any major issues, and produce a NET6 MVP. This will provide a 'golden path' for demonstration purposes and for grabbing screenshots of the Terminal app in use for the portfolio site. From there, additional fixes and enhancements can be planned and later implemented as necessary.
I bumped into a Microsoft Learn event that occurred in April: VS Code Day 2023. Silly name, however the content is focused on productivity using VSCode. There are definitely things I could learn about VSCode to help me out, so this is in the queue, too.
Interesting email regarding a job opportunity not far from home. After some research, I submitted a resume. The research was helpful, but the company is private, so information is (relatively) limited, and I don't subscribe to information-gathering services to draw from. I am interested to learn more about the opportunity because the description was a bit lacking, however I look forward to asking about the role and its responsibilities if the opportunity arises.
I've moved back over to my Windows development machine (nothing is wrong with the Linux environment). I discovered my NPM installation is a little behind, so it took me a bit to get it up to speed.
Upgrading NPM on Windows Key Takeaway:
npm install -g npm
for versions GT 6 but note this will upgrade to v.9.x!I recall reading about GitAttributes having some overriding effect on local git configurations. Bigfoot Bib Report is a Windows-targeted project that I partially developed in a Linux environment, later to discover an issue with LF vs CRLF handling. Previously this was handled by setting up a CircleCI pipeline to re-write the text file with CRLF symbols in place of LF. That worked. Going forward, I wanted to see if GitAttributes would solve this problem going forward without using a pipeline. GitHub Docs has a nice little write-up.
Git Attributes and LF vs CRLF Key Takeaways:
* text=auto
which is usually an okay setting.text eol=crlf
which will force Git to maintain CRLF symbols instead of strip them down to LF symbols.Initial testing indicates this will work. I look forward to feedback from the other contributors and users once they get this latest version (probably late July and early August).
Second iteration working through Quicksort was close but did not complete passing all of the tests. After some additional research I realize my mind was stuck on thinking of partitioning the array as an equal, symmetric operation. It doesn't have to be that way. For this challenge it might be better for me to think about solving the sorting problem by filling the ends of the array first. In other words instead of just picking the first index with a value that needs to be in a different position, find the index with the value that is most likely to be put at one end of the array. This requires sweeping the array several times, however after the first few sweeps the largest elements should be near the ends, and any elements still of the 'wrong side' of the array can then be managed within a sub-array (partition) without worrying that the out-of-order item will get 'cut off' from the rest of the array (and therefore never find the index where it belongs).
Worked through another iteration of Quicksort. Some corner-cases still failing (actually, corner-cases are good now its the golden path that won't pass). Seems like a large enough value at the end of the input array won't get moved far enough to the left. Will debug again on another day.
At some point I need to start figuring out how to use anonymous method and lambdas in Java. I have no problem using lambdas in Java when I see documentation showing usage, but it has yet to materialize without assistance.
Continued working on Quicksort algorithm in between other projects. So far this second attempt seems close, although it feels like cases where inputs have duplicate values might fail completely. Once I finish off the core logic, refactoring code to the new implementation plan will begin, in tandem with regular unit test executions to guide the refactoring process.
Assisted Ryan getting his local environment working for LingoBingo. The tricky parts were:
Over all it was great to work through the issues in a remote pair programming session that results in a working environment!
Returned to designing a Quicksort algorithm and implementing tests and code in Java. It was close, but failed on 2 fronts:
The plan is to return to this challenge in a day or two with a tiny bit more research, and a fresh perspective on solving the problem.
Lots of emails with questions about the volunteer exercise coming up on Saturday have been distracting me. Despite this, here are some takeaways from today:
Much of the weekend was spent at volunteer events. On Monday the 24th I configured Netlify to deploy a test build branch based on my updates over the last several weeks, incorporating Auth0 and API calls. It works, however there is a problem and I suspect it is a timing issue when an API call is made but the page renders without a valid response.
CodeWars has been acquired and has had a bit of a redesign, including a restart of their email campaigns that I hadn't seen for several months. The latest email had an interesting code question: How to verify a Sudoku puzzle has been solved. I started fiddling with possible solutions in between other tasks.
Completed two JavaScript code challenges and posted them to js-code-challenges. Added GHActions to run tests prior to merging, updated README notes, and added code commentary to analyze code in Big-O notation.
The antenna swap activity was successful and the repeater seems to be functioning properly, although it hasn't been tested to determine if signal quality (or coverage) has improved at all. At least the site has an actual 'repeater antenna' that has been used in that purpose before, so I have hope that it will perform well for many years to come.
My day was a little blown up with final prepping for several upcoming volunteer activities. However, I completed some interview preparatory tasks, got back into Microsoft Learn training paths, and also supported Code Fellows students by attending and interacting in their mid-term and final presentations.
Microsoft Reactor has been ramping up their informational and educational sessions. Three that are interesting to me are all happening today.
It's that time again: Update the resume.
While researching job openings I noticed quite a few that are looking for SQL Query skills. While I have worked with SQL relational system before, and am currently working with Mongo DB, I felt like the question "write a T-SQL statement that would return a list of book titles, sorted by author" would be met with a lot of "uhh" noises from me, so I added a task to review SQL Statements to refresh my memory.
Did some refactoring and debugging on LBJS front-end:
prop-types
is not necessary as a hard-and-fast rule in React, implementing it has helped me to keep straight in my head what types I am passing around between Components (and how many).Did some Git cleanup on this article. I occasionally delete older branches and found a missed branch that was never merged-in to main, with some comments from August 2022, so I got it merged in. There are a bunch of administrative catch-up items I need to complete this morning, then do some preparatory work for 4 upcoming volunteer events that will require completing and publishing plans and notes from previous meetings, as well as preparing hardware for in-the-field operations over this coming weekend.
I updated java-code-challenges with some refactorings of code and tests that I did a few weeks ago:
There is some more work to do with the code to "clean it up", but it is in a much better place now and it can be loaded, code can be edited, and tests developed and executed in VSCode now! :bang:
Lots of work with React and Express today, working through implementations for LBJS. Key takeaways:
useEffect()
has consequences. Know (or find out) what they are, how to work around them. Good rule of thumb is to change your logic to do something different to get the desired end result, instead of blaming useEffect()
and having the same (bad) result.
push()
ed into another array during processing.React does this thing in development where useEffect()
executes twice - once to test the integrity and setup of the Component, and again to actually execute it. react dev documentation walks through why this is and how to work around it. There are still edge cases where it will not fix a problem and presents some options for resolution:
I also read through a section of Baeldung's Java Streams and took some notes in my Java Streams Reading Notes.
Finally, there were a few interesting job opportunities posted recently that I need to research and circle-back to.
Lots going on ending last week:
I still need to test published deployment using 'deployed settings' for both SPA and API Server.
Saturday and Sunday were spent working through implementing a componentized and state-managed design to the front-end:
Lots of effort was put into volunteer projects yesteray and today. Now I'm back to the program.
CodeWars: I hadn't done one of these challenges for quite a while so I decided to do a technical design practice and follow up with actual code. Apparently this was a good idea because:
Key takeaways:
shift()
, reverse()
, and unshift()
are surprisingly easy but could be O(n) operations under the hood (I don't know) so if I'm going to use them I need to be prepare to talk about how they work, otherwise my code analysis will not be accurate.Number.parseInt(string, radix)
but I have to remember my assumption that the input is a String and if it is not NaN
will be returned.const array1 = [];
console.log('array1 size is', array1.length);
array1.push(10);
console.log('array1 size is', array1.length);
array1.push(20);
console.log('array1 size is', array1.length);
// altering items in an array can be done with replacement
array1.push('40'); // a String
console.log('array1 contents', array1);
array1[4] = Number.parseInt(array1[4], 10); // parse String to an int of specified radix
console.log('array1 is now', array1);
// js arrays can contain different data types
array1.push('a');
console.log('array1 size is', array1.length);
console.log('array1 index 3', array1[3]);
console.log('array1 contents', array1);
// shift removes element at index 0 from an array and returns it
let index0 = array1.shift();
console.log('removed item', index0, 'from front of array', array1);
let alpha = array1.shift();
console.log('removed item', alpha, 'from front of array', array1);
// unshift adds elements to beginning of an array
alpha = array1.pop();
console.log('array1 is now', array1);
let fourty = array1.pop();
console.log('array1 is now', array1);
array1.unshift(alpha, fourty);
console.log('array1 is now', array1);
// Number.parseInt() is helpful but might provide unexpected results
const number = 'letter';
const letter = Number.parseInt(number, 10);
console.log('string', letter, 'is now Number', letter);
Interesting discussion with a person at the dentist office today about the tech industry, layoffs yet lots of openings, how fast the software world moves, and building portfolios.
Did a bunch of studying and redesign planning in Express js for my custom API server. Some key takeaways:
Back to Auth0 challenges from a week ago:
My plan going forward:
Whelp, that wasn't really the problem but that's okay. Since using the canned SPA (React) and API (node, express) code does not get the data the API needs, a different route will be taken tomorrow:
For the rest of tonight I am working through a small code challenge: Find the 'middle value element' in an array of elements, and return its index.
This morning was dedicated to doing some catch-up work due to my heavy focus on code and environment setup last week.
Completed the task of documenting how to use VSCode for Java projects. It is very sparse comments that covers:
The best resource for this is Java Project Management for VSCode at code.visualstudio.com.
Spent some time looking through Baeldung Java 8 Streams, in the hopes I will exercise my previous learnings, build on that knowledge, and expand my Java skill set.
Focused on implementing "Remove Node" and "Remove Edge" functionality on the java-code-challenges repo's Graph class. When I originally built this class and came to the point of having to remove Vertices or an Edge, I didn't have a clear path to a solution, and the ideas I had at the time were inefficient and difficult. With a little dry-erase modeling and design work, I discovered the problem is fairly simple (although there is probably a more time-effeicient way to do them).
Removing an Edge in a Directed Graph:
Removing a Vertex in a Directed Graph:
Looks like moving to VSCode to do Java development and testing is not too tough, and the Extensions have enough smarts to use configuration-style project setup, or file-hierarchy style project setup, as well as integrate Gradle or Maven.
Spent the morning configuring my main workstation Windows installation for development work. VSCode and Git and various support files were already installed, and some configurations were good. Git needed to be updated to support CRLF in a Windows AND Unix friendly way. Some takeaways:
I still need to confirm my Windows workstation can play nice with:
Learning to get comfortable with Linux has been a journey that I've enjoyed and am sure will help me in the future. For now, I want to expand my ability to develop in both Linux and Windows environments. This agility could come in helpful for future employment, as well as when I am home and away from my primary Linux workstation.
Cloning to a Windows machine from a Git Repo that contains files with unsupported file name characters or filenames that are too long, will cause a Clone problem. Good news is Git provides a helpful message:
error: invalid path 'license.'
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry with 'get restore --source=HEAD :/'
Installing WSL seems like a good solution for this. The inconventient result is a reboot is required to complete the installation and configuration. Additional takeaways:
wsl --status
command for step-by-step help and be sure to run 'apt-get update' to get the latest deb references to allow installing new and latest packages.This worked, but took much longer than expected because its not everday that I work with ssl certificates and a credential manager. For my future reference, some key takeaways about adding SSL Credentials to Git:
ssl-keygen
.Git Credential Manager
or the latest git-for-windows
to get the manager installed locally (rather than use the cache).credential helper
Git configuration to manager-core
(or manager
which might be deprecated).ssh -T git@github.com
per instructions from GitHub Docs.Also: If credential manager is already setup in a host Windows machine with WSL 2.0 installed, the WLS OS VM can access the existing CredMan installation and use that as its own configuration.
Spent more time tweaking VSCode for Java development, and working with the Testing and Debugging tools (for Java) in VSCode. I was able to import an existing project with a large file hierarchy, edit files, run tests (passing), and do the usual git operations.
The Bucket Sort experimentation took several more hours of my day. I was exploring the performance implications of various changes to the algorithm, and trying to understand the algorithmic complexity through the modular method calls. At some point in the future I want to design Bucket Sort again, from the ground up using a TDD approach.
More on getting tests set up for Java in VSCode:
{
"java.project.sourcePaths": ["src"],
"java.project.outputPath": "bin",
"java.project.referencedLibraries": ["lib/**/*.jar"]
}
Testing Java in VSCode has more detailed information.
At first I selected JUnit Jupiter and it wasn't clear if fully supported (turns out it is fine).
Some takeaways while working with solution designing, Java coding, and Java debugging:
IllegalArgumentException
. The calling function should provide the necessary parameters for a fully fledged object instance, so it is up to the caller to handle that exception.Comparable<T>
is a fancy way to ensure a method only consumes comparable types, some work might still be necessesary to work with non-numeric types for example: Sorting words or characters within boundaries is not as straighforward as sorting numbers within boundaries. Not impossible, but could require a bit more design and code.LinkedList
with an ArrayList<T>
be sure to instantiate each element before attempting to access or modify it.About generating random numbers in Java:
Random rand = new Random()
is simple to remember and implement, the Random class has the problem of not being very random when instantiated within a function every time it is called. Instead, instantiate it within a Field of a longer-living Class instance to get better randomized results.java.util.concurrent.ThreadLocalRandom
library instead.Took care of some administrative and volunteer stuff.
Worked through some code challenges:
Developing Java in VSCode is a matter of installing supporting tools:
Long day of battling Auth0:
So much for Monday, hello Tuesday please be more productive!
I took a look into using GitHub Actions to enfore code style. Because Prettier is pretty great, and is now included with VSCode it is becoming fairly ubiquitous. GH Marketplace has a prettier-action that would do the trick. I'm not sure I feel comfortable with it adding a Commit to a Push or Merge. However, it has a dry run parameter which will fail the Action if Prettier has to make changes. The remaining challenge then is to ensure the settings in the GH Action match the actual desired codestyle and the VSCode user profile Prettier settings are in-sync. And isn't that the problem to begin with? With some experimentation I got it to work and will use it as a (potentially ongoing) learning experiment on my Portfolio project. Key takeaways:
prettier_options
are added. An example in my case: --check **/*.{js,scss,css,json} --single-quote --jsx-single-quote
.Finished up a version of Merge Sort that I can be happy with. Some takeaways:
The final Merge function turned out like this example code:
public void merge(int start, int midPoint, int end, int[] inputArr) {
int leftIDX = start;
int rightIDX = midPoint;
int tempIDX = start;
int[] tempArray = new int[inputArr.length];
while (leftIDX < midPoint && rightIDX <= end) {
if (inputArr[leftIDX] <= inputArr[rightIDX]) {
tempArray[tempIDX] = inputArr[leftIDX];
leftIDX++;
} else {
tempArray[tempIDX] = inputArr[rightIDX];
rightIDX++;
}
tempIDX++;
}
for (int fillIDX=leftIDX; fillIDX < midPoint; fillIDX++) {
tempArray[tempIDX] = inputArr[fillIDX];
tempIDX++;
}
for (int fillIDX=rightIDX; fillIDX <= end; fillIDX++) {
tempArray[tempIDX] = inputArr[fillIDX];
tempIDX++;
}
// the following built-in array copying utility was added by the IDE
// my code was a for loop from start to end, tempArray to inputArr
if (end + 1 - start >= 0) System.arraycopy(tempArray, start, inputArr, start, end + 1 - start);
}
Worked through a Merge Sort algorithm challenge. Started last night, whiteboarding the basic idea behind the solution. Came back to it today to do a full technical interview style solution. It took about 3 hours total including writing actual code and the golden path test. While the code is not fully vetted, this is arguably the best I've been able to implement a Merge Sort algorithm without looking at a reference to get through it. Key takeaways:
// find "left" sub-array and "right" sub-arry of an input array
public void partition(int startIdx, int endIdx, int[] fullArray) {
// if endIdx is 6 then mid = 3
// if endIdx is 7 then mid = 4
int mid = endIdx % 2 == 0 ? endIdx / 2 : (endIdx + 1) / 2;
// assigning startLeft for clarity
int startLeft = startIdx;
// assigning endLeft to be last IDX of "left" sub-array
int endLeft = mid - 1;
// assigning startRight to be mid aka first IDX of "right" sub-array
int startRight = mid;
// assigining endRight for clarity
int endRight = endIdx;
// call another function to process "left" and "right" sub-arrays
var result = processLeft(startLeft, endLeft, fullArray);
}
// avoid adjusting the incrementing indices within nested loops
// instead just have the loops do the work for you
public void merge(int startLeft, int endRight, int[] fullArray) {
for (int leftIdx = startLeft; leftIdx < endRight; leftIdx++) {
// by forcing the inner loop to start 1 index greater than outer loop index
// the inner loop auto-adjusts and never gets overlapped by the outer loop
for (int rightIdx = leftIdx + 1; rightIdx <= endRight; rightIdx++) {
// compare values at array leftIdx and rightIdx and call a shift function
// to move higher-value item at array rightIdx to the leftIdx location
}
}
}
Took care of some administrative stuff this morning, and cleaned up a couple notes files from previous events.
Reviewed Graph data structures and a custom method I developed (by hand) that find accumulated weight between two vertices. Also updated TODO lists with completed tasks.
While reviewing job postings I found one on LinkedIn that turned out to be click-bait. That makes job hunting that much less fun, oh well.
I was out for a bit, and when I came back I reviewed "Zip Linked Lists" challenge and made some minor changes. This is tight, well designed code. There is room for improvement in the tests themselves, but adding To String overrides allows visualizing the test inputs and outputs for confirmation that the zipper code is doing what is promised.
Reviewed Promises again. Maybe this time it'll stick. Just for the record, in recent weeks I have been using Promises correctly, and have also been implementing async-await whenever possible due to its simplicity. It is also worth noting that a Top-level Await in JS Modules is not available and newer browser support is pretty good (see MDN).
Attended a MSFT Reactor "Monitoring Azure Resources" event. Hoping this will provide some basics on adding monitoring to my AppService deployments. Somehow, I've missed a regular MSFT Reactor newsletter offering with more info about virtual and in-person events, until today.
Bumped into an interesting way to avoid compile-time warnings of Unchecked cast statements in Java. See Java Exceptions and Scanner for details. I also cleaned up that exceptions and scanner content for readability.
Completed a code challenge for Java to practice using File IO and NIO: Build a console application that will return the count of characters within a provided text file. This took me about 3 hours to complete from design, through implement, test, refine, and document. I updated java-code-challenges with the results of this exercise.
Researching SWE openings recently I've noticed more Java Kafka
positions. This is the first I've heard of Kafka so I took a peek. It is a framework for processing and presenting 'big data' for your applications or services, in Java. It is open source, based on Java 8+, and abstracts away the complexities of big data so your app can adapt to the Kafka inputs, and not worry about processing large amounts of data. Sounds interesting! I've added a task to take a peek at Kafka.
Reviewing Insertion Sort and Selection Sort, two key takeaways on the basics of these 2 algorithms:
Spent several hours trying to debug an Auth0 problem:
Completed some administrative and wrap-up work left over from last week.
Completed integrating Auth0 into a dev branch of LBJS. Key takeaways:
Started working on API calls using authorization:
fetchAuthConfig()
method and a createAuth0Client()
method that I want to look into utilizing to simplify authorization calls.Continued working on authorized section of LBJS. Key takeaways:
Working with LBJS attempting to get a page of forms designed for this next version. My initial idea was to use Bootstrap Accordions and Forms, and of course Accordions gave me trouble. Key takeaways:
as
attribute, which sets a custom element for the current component.The JavaSE Tutorials on Basic IO are quite long, and I'm nearly done studying them. Hopefully I'll have a better grasp on what I'm doing next time I need to work with Files, Scanning, and Streams in general.
Reviewed Hash Tables data structure and methods. Did pretty well, and could probably be conversant about the topic. Coding one without help might be mostly successful - not quite there yet.
Researching algorithmic complexity, it is good to remember:
Completed Insertion Sort code challenge. This was difficult. Key takeaways:
Equals()
and CompareTo()
on Generics and Types.HashCode()
and a CompareTo()
override or overload to get sorting to work properly and without runtime exceptions.Job hunting has revealed many more advanced position openings in the last week or so. Also, several interesting positions are looking for AWS experience that I would need to brush up on. I have a few backlogged projects I'd like to work on that would support using AWS tools, so I am inclined to consider how to reorganize my task log to make room for that.
Working through a code challenge to sort an Integer array I realize my sort algorithm knowledge is lacking. I kept trying to implement a merge-sort algorithm but couldn't quite get it working so I fell back to a simpler, very inefficient, selection sort-like algorithm. After coding and testing this, I will take some time out to study and analyze other algorithms.
Working through the Java SE documentation on Streams. Code Fellows curriculum covered this, but I need this added context and detail to get a better handle and to know when and how to use them:
static final String[] myArr = { "alpha", "bravo", "charlie" };
Ryan submitted some comments on PRs and merged a few in to Main. One issue was an inefficient check performed at every Game Session load (whether starting, during a game, or playing again) that was O(n) in time and space. I wasn't sure I could solve the problem, but after some studying and trying things out, I found an O(1) time and O(n) space solution that should do the trick. This also eliminated an additional useEffect()
hook, further consolidating code into an existing hook with similar dependancies.
Completed a code challenge adding one Binary Tree to another. It was completely incidental that I ran into this challenge, and it just happened that designing a solution worked well in my current workload -- better than some other tasks would have. Key takeaways:
I added to my network a little bit, but I still need to update my resume.
Reviewed an Azure Friday episode Developing Azure Functions using v2 Programming Model for Python. This breaks down to decorated functions that Azure Functions Service recognizes and deploys accordingly, and there is a local (virtualized) dev environment for rapid ramp-up.
Completed my weekly retrospective, stored elsewhere. I know what I need to work on, I just need to keep moving forward and keep my head up along the way.
Prettier was integrated into VSCode recently, which is great! There are some things to know:
.editorconfig
file, its settings will override Prettier settings stored in VSCode user config file.<Row className='p-2'>...</Row>
is JSX and has a String in the className. JSX Single Quote is the Prettier setting that needs to be enabled to enforce this.className
and tabIndex
, among others.Review React Documentation on JSX.
While researching open positions with a C# / Scala team in US-East, I uncovered a bit of an interesting rabbit hole, discovering different views about investing, decision-making, and meritocracy. I don't believe the company/team would be a good match for me, but I came away from the research with a few notes and slightly changed view of the world...an unexpected takeaway.
Reviewed java code challenge: Binary Trees and decided to merge-in the PR as-is. There will always be more to do, but not right now.
Completed some administrative tasks, and discovered I should rework my social media follows a little bit, and also try to squeeze in some official podcast time so I am more regularly introduced to on-going tech topics.
LBJS on Netlify work takeaways:
_redirects
file in the public
folder (for React, might be elsewhere for other frameworks) to include index.html
and force an HTTP 200.Create React App documents on deploying to Netlify.
It's practically Thursday and I'm just now writing about my day.
I completed some interview prep and job hunting tasks. There were a couple of interesting openings - one required relocation (would pay but I'm not interested in moving right now) and another was not a well formed job opportunity posting, just failing to describe the job or who the hiring manager was looking for. I did pick up some good insight into what a few teams were looking for in a candidate, even if the experience or other aspects did not match well for me.
Self tested on some data structures and algorithms, and completed a code challenge: Whiteboarded a complete solution in 45 minutes with analysis, test approach, step through and code, and then validated the code in Java with tests. Along the way discovered something called a TreeSet: A Java utility class that provides sorted data. I didn't research it completely, and am assuming it is a Binary Search Tree. This was useful for ordering a large number of inputs to get the largest value (last sorted item) without knowing what the values were, so a unit test using large random value inputs could be used to test my code.
Back to LBJS:
Happy Pi Day!
This morning I continued development on the Binary Tree class, completing implementation of the remove()
function, verified tests passing, and performed some general code cleanup. There are a few more things I want to get done with this code challenge, but it will wait for another day.
I found a few software job postings online today that were worthy of some time to research.
I also reviewed my previous java code challenge work on Graphs. There are some issues with the Readme content, and perhaps sometime I will address that. For now it stays as-is. However, I came away with some thoughts about using HashTables and Sets to store unique values for later lookup (Graph, Traversals with Visited Collections, etc):
Started researching Java Streams and making notes here.
Put some time into designing Binary Trees, continuing from yesterday, and also started coding tests and implementing from designs. Key takeaways:
hasRightChild()
and isLeaf()
are implemented.souf
(template for System.out.printf("")
with %s
, %n
, etc) instead of sout
to easily in-line string formatting.public Stringn toString()
method will help with debugging if crafted to expose necessary fields and values.About Binary Tree Nodes vs their (possibly) containing Classes:
I plan to add the ability to find the Height and Width of the Tree, as well as implement recursive depth-first traversal, as well as a generalized breadth-first traversal function. At that point, this challenge should be done, effectively replacing the older binary tree implementation.
Completed some administrative tasks including end-of-week retro. Since I have missed completing my retros on Fridays, I'm going to reset the goal to Saturdays instead. Seems to make sense anyways because I track weeks Sunday through Saturday.
Whiteboarded some Binary Tree structures and traversals, but somehow am getting stuck on depth-first. I'll need to work on that tomorrow (I know it, just need to work it out again which is good practice). This is in preparation to replace my Binary Tree implementation in my java-code-challenges repo.
This morning was a little disrupted with a vehicle repair situation, followed by a drive to Puyallup for a ham convention and electronics show. I met up with a few hams I have volunteered with in the past and we caught up a little. It was good to get out and be social.
At home I designed a set of functions using Java, on a Singly Linked List to do various things:
I still need to do my end-of-week tasks, but that will have to wait until Sunday.
Completed a code challenge on a real dry-erase board with pseudocode and step-through (excluding BigO analysis and tests).
Attended a Code Fellows Code301 Final Presentation session. The Code301 curriculum has been updated with React Hooks and WebSockets. I am a little envious about this, but I have already started to use React Hooks, and can always add Sockets as a topic I want to explore in the future.
The MS Graph project is not very exciting to me. I thought it would be, but I find myself not getting excited about interacting with MS Graph, and feel like I am putting more into it than I am getting back, so for now I'm going to set it aside. There are a few more days left so I might go back to it, meanwhile there are tasks I am passionate about, so I will pursue those.
I completed some LBJS activities, and with some research and experimentation came away with these tidbits:
Later, I set up my SurfacePro 7 VSCode with Java development Extensions and it is working well for dev and simple debugging. I will need to learn how to set up unit tests as well as find build output (JAR) files, but that will come in time. Using this setup I coded (in Java) the code challenge from earlier today (a singly linked list) and starting building out additional functionality:
Lots to do today. For starters, attend an MS Reactor presentation on TS: Deploying React+TS App with Azure Static WebApps. Next, some volunteer administrivia finalizing a capabilities diagram and sending a few follow-up emails from last nights meeting. Then, to finish up the morning, complete some job research and preparatory tasks. This afternoon I'll get back to MS Graph development, and try to sneak in a technical challenge or two. Friday is usually a busy morning, and Saturday I'll be at another event for a large portion of the day, so today is probably the last 'full day' to get some impactful things accomplished.
I'm realizing that I can be organized and yet still experience some chaos of my own doing and from outside inputs, without concluding I lack structure.
Holy wowzers it took me 2 hours of fighting with DotNET ConfigurationManager extensions to figure out how to get environment variables into a console app. Good news is I DID IT. Key takeaways:
.SetBasePath()
, and .AddJsonFile()
.Directory.GetCurrentDirectory()
.BuildConfig(IConfigurationBuilder)
method operates on a an object instance reference :arrow-right: Whatever argument is put it must meet IConfigurationBuilder
requirements and will be 'configured' in-memory.BuildConfig()
just ask for the data you want i.e. builder.GetValue<T>("parent:childKey");
Took some time out from the MS Graph project and studied some OOP and C# lessons from a few years back. It is interesting to see the anonymous functions, Delegates, and other keyword implementations after studying JavaScript and Java for the last year and 6 months (respectively). I can't believe I had such a hard time with data structures and algorithms in Java, given that I had already be training those concepts in 2021. Anyway, it was good to go over some of this and I'll count that at code challenge studying for the day.
Back to MSGraph: I was having an issue where authentication was failing in a weird way. The message indicated that the wrong tenant was selected for authentication. It took a bit to figure out which portion of my setup was bad, but the only thing remaining was to verify my app was properly registered (was the ClientID correct?). I remember creating an Application and setting a ClientID, but perhaps that was deleted after my first (very rough) attempt to develop this hacky solution. Once I went back in and registered the an and set the ClientId, the code would run without hanging or throwing, and data was actually returned.
Spent a good amount of time reviewing code already written for LBJS API server and finding some places where things could be improved, and updated the uuid generation to use base64url encoding instead of hex. I was originally going to implement Secure Cookies but I'm going to table that effort for now, and put a work item in my backlog for focusing on later. For now I need to spend more time in front of MS Graph and C# so I can submit something for the hack-together event.
On Monday, before diving deep into the API Server, I did some research on a few companies. Nothing terribly exciting has come up yet but it is interesting to see lots of job expectations, company values, and ways companies interact with the internet.
This evening, my MS Graph project could no longer get past authentication. The problem might be related to my changing the app.config file (per docs) but I'm not sure. Will look into it tomorrow morning.
Continued working on LBJS API Server, reviewing the implemented paths and refining the code, runing manual tests to validate functionality and crash avoidance. Utilized whiteboarding to work out logic fix-ups and refactorings for some functions. There is still work to do here but it is better. Began researching SecureCookies, which seem simple enough, just need to figure out the proper syntax to get the secure key working. Current thinking is to use a secret salt and just go with that. One concern is dealing with these massively long UUIDs - it might be good to use URLEncoded or some other conversion or digest method to keep the IDs from becoming too long for the frameworks to handle them (introducing unexpected results and matching or authorization bugs).
Did some job search work and updated lots of administrative items and documentation. I also completed a week-end retro for this week. These are helpful in setting a pace and expectations going forward.
Whiteboarded some new appoaches to existing API Server functions. Turns out there were some issues with some routes and also the default error handler. One route issue was checking for situations that would never occur because the cookie handler middleware would have caught it, leading to cleaner code. Takeaways:
next(message)
if there is an error, otherwise always if-then through all scenarios that apply.next(error)
in the catch after any logging statements so the default handler catches the 'err' condition in middleware.There are 7 more tasks to complete before I will feel like the API server is in a good-to-go state.
Some developments this morning:
List<T>
or ArrayList<T>
). Everytime this happens, the code gets larger and does not meet the requirement of using a bracketed array.Completed the Java Generics exercises, and experimenting with the code and tests I produced.
I updated the MS Graph code a little bit. There is much more to do and learn. The main hang-up right now is figuring out how to handle the result type from a successful, filtered request. It is not obvious to me.
Attended another seminar on Microsoft Graph API and SDK, and signed up for the hack-a-thon challenge at MS Hack Together. Initially I considered a Java-based Android app for my submission, but the DotNET SDK is a requirement for entry, so I'll stick with that. It took some time to get used to how the Graph Explorer works, including permissions allowances to various endpoints. While using the tool I set up some ideas for project features I could implement, and wrote a Console App in C# with DotNET SDK 7. Key Takeaways:
Attended a seminar on Microsoft Graph API and SDK for DotNET. Microsoft 365 is building features and functionality on top of Azure services and the DotNET platform. Microsoft Graph allows querying for "me" data, meaning the API endpoint root is "me" and after authorization, the REST methods allow calling for calendar, email, task, and other data. MS Reactor will be holding more sessions about Microsoft Graph in the coming days and weeks.
Reviewed Java Generics on Oracle's Java Documentation. It went into much more detail than I had expected. It made sense although it was slow going at times. In the past I ran into issues with Generics and saw some warning messages that I didn't understand, now they make sense. For starters, the Raw Types message: This means the code risks operating without type safety, and Object is used as the base Type, allowing Boxing and Unboxing to occur, and unchecked Casts, which can negatively impact performance, or allow Runtime Errors.
Some other key takeaways:
<
and >
on Types, only Primitives.It's snowing again.
Worked on researching interesting job openings, and exercised my brain with some q-and-a practice early this morning. It's a good wake-up exercise once I get some food and a cup of coffee in me.
Snow stopped falling, everything is drying out now.
Took at a look at some job openings, more research is needed.
Decided to take a peek at the Portfolio webapp project from April last year. There were many issues, partly due to deprecated and vulnerable versions of modules, and partly due to various CSS and content problems. I took some time out to fix all of that and deployed a working version to Netlify. I added work items of things to fix and update to make this portfolio webapp a bit more appealing and useful.
Continued working with Graph data structure and completed the challenge: Write a function for a directed, complete graph, that finds a total value of a path between two vertices. Key takeaways:
Revisited updating dependencies of a React-JS webapp. Every so often vulnerabilities are found in node-js modules that probably should be cleaned up. Good news is, there are bug-bounties and free-lancers that find these vulnerabilities, so they get fixed in the OSS world pretty rapidly. Now the problem is for the implementers (dependecy dependers?) to update the node modules and redploy apps to avoid these attach vectors, for the sake of their own deployment, and their users.
Key takeaways:
npm audit
to make a list of installed, vulnerable packages and dependencies.npm update package-name
instead to update a specific top-level dependency.npm audit fix
is also an option and will be helpful to automatically resolve some (or all if you're luck) vulnerable dependencies.npm audit fix
again to force acquisition of the correct dependecy/ies.Plenty of bouncing around today, between the Graph code challenge problem solving design efforts, and catching-up on LBJS PRs and enqueued work.
LBJS: We are very close to a point where we can launch V1 front-end and utilize the deployed API server to get existing gameboards if needed. We have means to authorize for adding words and creating gameboards all on the backend, so custom requests can be made. There are just a few bugs and a couple loose ends to resolve on the front end before pushing the latest to Netlify and basically having V1 ready-to-go for players.
I realized that instead of manually editing package.json and package-lock.json files I can use npm to manipulate dependencies safely. There are a few situations where manual editing is still required, but a lot of the complexity is gone now that I've worked out and refined a step-by-step.
Promises made a return, related to an Axios call in a useEffect on a React site. Some takeaways:
async
and await
instead of Promises, they are just easier.See conted index for an entry about Promises.
Ryan got back to me about some updates I supplied to him earlier in the day. He raised a good question about a PR that I submitted, so I went in and fixed it. I need to watch for obvious code-line omissions, kinda like 'copy-pasta' problems.
Worked on a few administrative and interview prep tasks, and watched an Azure Friday episode about billing: Monitoring and Reporting. This was timely since I recently started getting charges for a couple of AppServices (dimes and quarters worth, so at least it is small).
Working through a tougher Java challenge: How to get the weight between multiple vertices. Key takeaways:
I'll take a look at this again tomorrow, and I'll use a Stack rather than recursion to solve it. This way I'll have full control over the exit from the search pattern.
Thursday was spent designing, testing, fiddling, redesigning, coding, and testing Graph class. The key takeaways are:
.equals(obj)
instead of ==
operator..equals(obj)
and operator overrides so the JVM can properly differentiate same-for-same values within custom objects (otherwise it will always see them as different memory location mappings regardless of values stored in them).Friday morning I made the mistake of trying to change Themes to get something closer to VS Code's Night Owl custom Theme. There is one, but it is NOT the same. Also, I don't understand how changing themes in IntelliJ can possibly be fun. Couldn't they have just added a one-stop-shop to import, use, change, and edit UI Themes?
I continued with more redesigning and test-driven development with the Graph Class. Key Takeaways:
for(...)
or for(each)
loops when items are going to be removed from a Collection.hasNext()
, reassign REF using next()
, and removing the last item returned with remove()
.Back to code challenges:
Some takeaways from working on code challenges:
hasNext()
to test for an item, and then next().value
to get the value is helpful to rapidly find whatever value is 'next' in a specialized Collection like a HashSet.Worked through interview preparation tasks. I need to review some documentation from back in June and July '22 to refine my preparatory tasks, resume, and etc.
The live stream about Windows Subsystem for Linux was canceled.
Back to the drawing board to figure out the logic necessary to bulk-load words into a DB via an API. I was practically dreaming about this problem last night. Whiteboarding the problem took about an hour, but the resulting code works better than any of Monday's attempts. The final hangup is managing status codes and any result message. Gotta love it when the code works as expected, but the hang up is just error handling and final portion of the WRRC.
I generally find HTML Forms to be fairly easy to work with, with some referencing MDN for details and some syntax. Using PUG to display a form that will accept an array of strings was a little challenging. The key takeaways:
name="name[]"
but in PUG that does not work.Methods of cleansing and massaging a long input string into an array:
typeof myVar !== 'string'
etc.String.prototype.replace(regex, '')
to replace spaces with nothing, as an alternative to an iterator that does trim()
to each item.String.prototype.split(delimiter)
to break the string into an array.string.replace(regex)
to avoid importing executable code.Reviewed Graph Data Structures:
Approached LBJS bulk-load words via an API. There are some limitations (like only authenticated users can do this) and requirements that must be met (at least 24 words, and the database should not be polluted with duplicate words for a single owner) that results in some design and slightly more complex implementation details. First idea was okay and leveraged Promises nicely, but the logic did not work out - duplicate words were allowed. Second and third attempts were better but still some logic failures were allowing duplicates. I shouldn't have let 3 attempts go by before re-designing. Will work on this tomorrow.
I knocked out several interview preparation tasks and took some time out to reorganize and re-prioritize work items.
Knocked out a few more LBJS tasks including fixing code vulnerabilities in dependent node modules. Determining the correct set of steps to find and remove the vulnerable code was a challenge. This exercise led to some side-track investigations into a few things:
Ryan approved and merged-in a few PRs so I updated the Trello board.
Vercel has a getting started with Next.js onling training session that I should explore some day.
End of week retro:
Most of my time earlier this week has been spent on volunteer and around-the-house tasks. I will be presenting how to use "Email over ham radio" to a class of 12 hams on Saturday the 18th, and I think my presentation and plan is ready to go.
Completed an LBJS PR to componentize a pair of nested functions within a React Class component. After initial discovery and fiddling with the code I started to thing the effort was not going to be worth it. I took a break and thought about it, came back to it and implemented a slighly different solution that started working well. After a few short refactorings while testing, the webapp was working without errors. Key takeaways:
Watched a presentation on Linux on Azure. It wasn't too informative but I already have some experience with Azure services, so some of it was review. It was interesting to learn:
Knocked out an example 'favicon' file for LBJS. Was a good exercise in using creativity, Paint.net for image editing, documentation, and code management using git.
Completed a java code challenge, this time using a Queue data structure. Although I was unable to complete requirements of the technical interview, the diagram had good basic logic and required few edits to make it a good resource for writing pseudocode and actual Java code. Once I wrote Java code, about 4 lines of code needed to be removed, and there was only one small bug in the code that was quick to fix. All the tests, even the empty cases and those containing zeroes passed right away. One other positive takeaway is: I implemented a Queue class and Queue Node specifically for this solution and only needed to peek at a working solution once before the Queue implementation was fully functional (Peek, Enqueue, Dequeue, IsEmpty, and getSize/Count)!
Took some time researching Azure and Linux. Microsoft Learn has resources and training materials that I started in on. Hopefully this will help me take the next steps, which is continuous integration, and eventually continuous delivery. See notes added to linux references.
This morning I realized there was a problem with a test for the latest java code challenge so I fixed the test, which uncovered another bug in the latest revision of the code. I spend some time redesinging the code (to avoid writing really long and tedious garbage code) and came up with a solution. Some key takeaways:
if-then-else
can get really tedious. Options are to use if-continue
or switch() case:
to avoid crazy-nested decision trees.There are other data structures I will try to get a good sorting algorithm working for this code challenge.
I also spent some time working on LBJS front-end. When a user is given a link to the gameboard by the presenter, the website should load the appropriate words and randomize them so the bingoboard is ready for the user to play. Lacking an appropriate gameboard ID in the URI link, the gameboard should still load a canned set of words. Last week I wrote a possible solution and included a 'then-able' Axios call, but I didn't quite implement it correctly. Key takeaways using Then-able Axios:
.catch()
statement is hit, be sure to include any/all code that must be run following the error condition.console.log()
in React can be dangerous! Avoid using concatenations or template literals. Instead, just comma-separate text and values.On Friday I attempted to impelment the code I created during a 45-minute code challenge and it became clear there were many issues. So today I retried the same code challenge and it moved along pretty well. I utilize a different data structure and traversing it was a bit easier. The 45-minute timer expired before I was able to walk through the code visually, but there was code on the board, and it had been stepped through using the design diagram I sketched up. What was lacking was stepping through the code using the example input collection values.
The code challenge yesterday has one pretty bad bug that makes it a failing solution, and there were a few idiomatic and syntactical issues, docking a few points. Given I haven't written Java in a while, this is not a total surprise. Plan is to re-try this challenge soon and do a better job of defining the problem before building an algorithm, and then walking-through the algorithm (debug it!) before writing the code.
Worked with Ryan, sorting out Auth0 authentication configuration and use of JSON Web Tokens and Keys.
Slowly I am getting back to my weekly schedule. There have been enough interruptions the last few months that I have fallen behind on things like technical interview practice and other preparatory tasks. I am so fortunate I have the time and ability to put in this effort.
Completed a technical interview question that required code in order to 'complete' it. Initial rubric scoring of my solution indicates a likely pass, however I will need to review the idiomatic and syntactical correctness of the code (later today). One error I made was in code analysis:
After watching a presentation on algorithms and data structures, it occurred to me that during technical interviewing I often times get caught up in values. The presentation used colors as Linked List Nodes, rather than numbers or characters/strings. While it is true that values are important in an algorithm, it is more important early on to determine how to traverse a data structure. Walking the structure is necessary for the algorithm to process the values within it. Once a data structure and traversing algorithm are selected, plug-in the numbers while performing a walk-through to verify the planned implementation.
Some advice shared by David:
Made some experiments with LBJS React using Axios to acquire a payload from our custom API server.
Also took some time to execute the implemented routes on the Azure-deployed API Server and everything is working so far.
Attended MSFT Reactor session "Building Your First Typescript Project" and made notes in my Cont-Ed folder for reference. Key takeaways:
.env
file to set environment variables, use .envrc
and set it up the same as .env
, then create an app-config.ts
file, import zod
and create a z.object({})
with full typing for each environment variable. Include a try-catch with process.exit(1)
in the catch in case the config typing is ever invalid. Lastly, in the TS file that needs the config e.g. an Express-js app entry point app.ts
, load the configuration as a const e.g. const config = loadConfig()
. Config items can then be accessed using config.some_property
in the code.While working on what looked like a good fit for a Turnary Operator (which avoids writing yet another set of if-then-else codeblocks). While fiddling with the right Turnary Operator statement, I explored some alternatives and discovered that node.js will accept the Logical AND operator &&
followed by a Logical OR operator ||
:
function getCode(arr) {
return (arr.length > 1 && 200) || 404;
}
console.log('statusCode from [1,2,3]:', getCode([1, 2, 3]));
// output: statusCode from [1,2,3]: 200
console.log('statusCode from []:', getCode([]));
// output: statusCode from []: 404
MDN covers this in their JavaScript Reference documentation on Operators so there is no real surprise here but it was fun to stumble upon it while working on a real project. Fairly easy to read and less typing than if-else conditionals. Pretty neat!
Practiced whiteboarding while developing a route on the LBJS API Server: Problem statement, inputs and outputs, step-through definition (but no depictions/drawings), and javascript code (but no pseudocode). Took about 45 minutes to complete whiteboarding, perhaps 5 minutes to implement the code with only minor adjustments, and another 5-10 minutes of debugging and the code is functional! There are probably a few more bugs to work out, but only one major bug-fix was required to get the happy-path working as intended.
Implemented cache and Promises on one of the routes. All of this practice is paying off and implementations like these are getting easier, and are completed more quickly than before. I still need to add tests to the functions for sanity sake, and there are plenty of refactorings needed on most of the other routes... those things will be done in time.
The LBJS-Back API AppService has been redeployed with the latest PR code and it appears to be functioning! It can successfully return a JSON collection of words, and all of the existing routes are protected by default. Tomorrow I will do more testing using authorized users while watching the Streaming Log to validate API paths are doing the right things and Node.js is not falling over in Azure.
Spent a good deal of time battling Express Middleware and Error Handling again. I somehow allow myself to ignore the rules of these concepts, run into errors, and wonder why implementations are failing. Important aspects:
Chatted with Ryan to get up to speed with LBJS and we are both pretty busy lately. Overviewed the WRRC, current dev state of API Server to-be-deployed, and using Auth0 in a React (SPA). Will deploy a sample SPA that works with my Auth0 acct so Ryan can test and dev on his local using the working sample code.
This morning I attended a Microsoft Reactor live stream introducing TypeScript. I have some experience with TS as a test engineer but haven't tried developing with it yet. I'm not in a big rush to learn it, and this session gave me a pretty good idea about how to get started so I can start exploring when I'm ready.
Most of the rest of this week through Satruday was busy with other administrative and volunteer-orientated tasks.
Key takeaways for Wednesday:
findOne()
instead of find()
to limit results to the first Document, unless it is necessary to return a collection of matching documents (or all of them).updateOne()
has the added feature of reporting on whether the DB operation was executed, how many Documents were matched, and how many were upserted or modified. Output this information to a log so update transactions can be reviewed or audited.next()
.Key takeaways for the day:
npm -i
.Worked on the API Server a bit. Got caught-up in Promises and complexities of asynchronous server-side code. Will address this tomorrow.
Scheduled a meeting with Ryan to discuss LingoBingo for this comming weekend.
Was out of town last week and didn't do any coding or writing. Instead, worked on other tasks in between skiing sessions and other activities.
Busy week. Lots of dev Weds and Thurs that didn't get logged here, that's okay here's a summary:
Going forward I won't have much time for implementing and securing routes, verifying username/password authN and authZ, and adding caching. Before the end of the month I hope to have the API server in such a state that the front-end can call an open route and get a valid response, and soon after that get authorized requests working as intended. Additional social login types will have to wait in the backlog.
Some other takeaways about deploying a Node.js project to Azure AppService:
For the Nth time in a few months, I've found myself getting a little confused around Promises. At least it's a new year. Perhaps part of the confusion is I am mingling promises with Express middleware and custom error handling? In some instances the headers are getting rewritten (after already sent) and in others the system crashes instead of catching an error (despite being in a catch block). Some research followed by refactoring will be necessary to get this going properly.
Started working on what will be the production API server for the LingoBingo project. Basic API paths hierarchy is laid out, schemas are added, database connection is working, and some core functional modules are implemented. Next steps:
Security will be maintained through Authorization Validation checks and use of Write- and Delete-capable modules only on specified paths with input and processing guardrails.
Technical Datastructures Review, areas where I need to brush-up on:
Completed some interview preparatory tasks, and an end of week retrospective.
Completed writing up a summary of Firebase Authentication: Setup and Implementation. I still need to go back and do it again from scratch so that I exercise what I know, and learn what I don't.
Wrote-up notes on an Azure Friday episode about Azure support for Java Development. Microsoft released their own OpenJDK of Java 17 (LTS). It might be based on Adoptium.
Writing up some notes on error handling in ExpressJS. I left-off about 1/3 the way through the API documentation while implementing the basics on a few cached routes.
Other Key Takeaways:
String.toString(obj)
within a Node environment, even if you know the obj is a String, because it will come back as the String description of a 'native object'.'use strict';
declaration is not necessary within exporting modules, it is implied.Fiddled with PowerShell 7.x for a minute (2 hours). Now I remember one of the driving forces to find another language to learn and to get a better understanding of object-oriented principles. PowerShell has its place none-the-less.
Took some time to implement caching on the (private) getting-started API server:
A good portion of the rest of my day was spent preparing and emailing items in my volunteer capacity. It is set in stone (pretty much) that I will be running a training session, demonstrating basic Winlink startup and usage. Within a couple hours of the email announcement going out, the 'registration survey' already had 1 response, and I know there will be at least 2 more, maybe as many as a dozen!
Goals for Saturday:
For the first time in over a month I went for a run on Tuesday morning and I overdid it. So I ran again this morning and it was much easier so back to work!
Working on the Auth0 front-end:back-end authentication project:
checkJwt
that was pointing to the correct express server, but relying on the Auth0 API server, but other configuration code was missing in order to do JWT authentication in this way.jsonwebtoken
and jwks-rsa
node modules and set up an Authorize component that defined a client pointing to the JWKS URI (an Advanced configuration Endpoint setting on the front-end application page), a getKey()
method that acquires the public signing key, and a verifyUser()
method with a nested valid()
method, that acquires and formats the authorization token and validates in using jwt.verify()
.Now the front-end is able to access unprotected routes without an Authorization header, and CAN access PROTECTED routes WITH an Authorization header and a valid Token:
UseEffect is easy to get wrong, here are things I learned getting it wrong, then debugging and getting it right:
Happy new year!
Entering retro notes daily is a little overkill for my purposes, so I'm going to try a weekly branch => push cadence instead.
Deployed an example API server with canned authentication and data (no DB backend) to Azure App Service:
.env
or in Heroku's environment variables settings page.Going back to the React + Auth0 + Express example deployment:
Tomorrow I will get back to this and:
unexpected 'aud' value
is referring to 'audience' or something else.Express Learnings:
next()
is simply a matter of assigning a KVP to res.locals
, for ex: res.locals.authResult = 'Authorized'
will attach key:authResult, value:'Authorized' to the Response
handler.cookie-parser
than it is to dive through the headers manually.res,req,next
in the params list. In fact, the params list can be left out altogether when called in-line with a handler i.e. app.get('/', myMiddleware, (req, res) => { res.json({message:'Ok!'})});
.A markdown surprise: H1 Headings can be made using equals signs. It will render the same as # Heading1
.
Heading1
===
Demonstrated Firebase Auth and Auth0 capabilities to Ryan, for LingoBingo. We are both pretty confident that we can make Auth0 work with React FE and ExpressJS API Server, so we plan to start moving forward with server setup and deployment, and developing needed React pages.
Some more takeaways:
REACT_APP
.AUTH0_DOMAIN:"dev-asdfasdf.us.auth0.com"
they are value assignments i.e. AUTH0_DOMAIN="dev-asdfasdf.us.auth0.com"
.Random comments and discoveries:
const items = { numbersArray: numsArr, proportionsCollection: proportions }
..toBeCloseTo(number, numDigits?)
(numDigits is optional).I had a good lunch break with my friend Dave in Snohomish. It was great to catch up with him and to talk techie stuff over tacos and coca-cola.
Christmas week is over and it's time to get back to business:
Some key takeaways:
axios({ key:value, key:value })
.headers: { headerName: headerValue }
. This can be used to 'Authorization' header fields such as for a Bearer Token.response.data
, so a response that contains a JSON object with a 'message' field is acquired via response.data.message
when 'responseType: json' is used.Started working through integration of Firebase Auth into an ExpressJS server.
Attended a partner power hour presentation by Roger R, about Graphs, demoing a simple navigation app. Well done!
Goals for today:
Takeaways:
<Redirect to=...>
are now <Navigate to=...>
, and instead of using 'push', 'replace' or nothing.I ran into a problem with getting the user context back from Firebase...rather, I knew the user was registered (and logged on) but somehow my code was missing the ability to update the state properly so that the site would show the user was logged in and allow logout. After trying some things I ran across some web resources about using Firebase and decided to explore them. Because my React App was manually configured, the WebPack and ReactScripts versions are in a buggy state that blocks using dotenv 'process' properly. This is a super-bad situation and probably means the site could have other broken issues I might not want to have to fix, so I'm starting over using the standard Create React App method. argh
While working through an Advent of Code challenge, I found a need to develop a collection of custom Class instances.
Working through Firebase Authentication again:
ComponentDidMount()
to configure Firebase in the end, and it appears to be functioning!Will keep moving forward tomorrow, after a good night's rest.
Interspersed: Various administrative tasks that need to be completed, outside of coding.
Implementing Firebase Authentication required resetting to my Linux dev environment. I wasn't too interested in using NPX to set up my new React project for this purpose, so I did it by hand following (most of the) advice of vish448's Gist on GitHub. Vish448's method included installing and configuring WebPack and Babel (neither of which are well understood by me just yet) so I spent some time working through issues:
"presets":[ "@babel/preset-react" ]
and the site rendered.Quite accidentally, I ran across what could be a helpful article next time I approach Auth0 + React (soon!):
React State and Forms:
event.target
to get the Form elements submitted on an Event handler.<input name='username'>
...).Was ill last week and did not add notes here. Instead, I worked through several Advent of Code challenges and have completed the first 4 days' challenges.
Some takeaways re: Advent of Code solutions using javascript:
Lingo Bingo:
Saturday:
Sunday:
-[ ] Review Firebase authentication and determine if this is a viable solution for a current project. -[ ] Update Miro with new design thought and approaches to the back-end API server.
Completed some job hunting and interviewing tasks this morning.
Against my better judgement I took on part 2 of Advent of Code 2022 Day 1 challenge. I retro'd the outcomes elsewhere but in essence:
Completed end-of-week retro (elsewhere). While it was a good, productive week, there are areas where I can improve, so I will continue taking time and effort to better plan and execute my projects and time.
Fixed-up most of the CRUD methods in the exploratory API Server to ensure consistent output and status code returns. Still need to refactor OUT the req, res, and next from the gameboard functions module.
Had to do a git reset --soft <commit>
due to my running git commit -m 'message'
after an incidental git add .
when I meant to git add <file>
. Still not the ideal solution, but for this project the git history and messages aren't super critical.
I discovered that adding non-async calls to another module, from within an async function can really cause timing havoc. The best solution is probably to move to promises over async/await.
Mongoose provides for model validation within the schema, so I added that.
Completing implementation of 'deleted' (boolean) and 'updated' (dateTime) field updates was not too bad. The biggest hurdle was learning how to create a valid timestamp in javascript: const dateNow = new Date(Date.now());
. I modularized that so it can be called JIT from any other function that needs it.
I'm not too thrilled with Pug. While it is nice as a quick-and-dirty html templating engine, doing anything too fancy with it is just too tedious. Also, the documentation mentions 'native' handling of arrays, which is true, but then they use examples that are awful (using hard-coded values) AND what is meant by 'native' is an Array can be passed-in to the rendered Pug file, and it will just list it horizontally within a 'p' element without any additional effort on the developer's part. It is probably the case that the desired output needs to be processed prior to passing it in to the rendered Pug file? Not sure I care much about it right now -- if I wanted to do something truly good for the user, I'd just create a React App and be done with it.
Code Fellows hosted a "Code 401 Instructor Panel" as they have done every so often in the past. It is always enlightening, and usually uplifting. Today one of the instructors reminded the audience that honing expertise takes 10,000 hours, so keep hacking through the tough times and learning will happen along the way. This is a good reminder for me to consider where I was a year ago versus today, and 10k hrs is still a ways away, so I should not be expecting 'expert level code' by any means at this point. In other words: Keep at it, but take it easy on yourself.
The exploratory API server now has cookies fully implemented to use as an authorization tool for the various paths. Next goal is to get cache working on get calls.
Good places to start:
Skipping an authentication provider service for now, working with cookies takeaways:
It was becoming more and more clear that I needed to implement middleware and Express Routes, so I started working in that direction. The goals are:
Enabling cookies was definitely a good idea. Validating cookies is a bit more difficult. Refactoring the code lead to some typos that consumed lots of time, but I can 'login' and 'logout' using just cookies. Next steps:
Some things I learned:
return item1 !== undefined && item2 typeOf 'string';
the way I would have hoped.app.use(middleware);
statement are super important to pay attention to.Goals for Tomorrow:
Auth0 struggles stole most of my day. There were a few other interruptions too, and that didn't help. Key takeaways:
Cookie exploration was interesting. I had forgotten a lot of what I'd been exposed to 20 years ago in college. The challenge then was learning how to use the cookie-parser middleware function. High level takeaways:
Request.cookie
, and key-value data can be captures with property selectors (e.g. req.cookie["foo"]
returns a cookie with value 'bar' if it was set).response.cookie(Key: String, Value: String, { options })
.The basic plan going forward will be to use Cookies only in very specific places in LingoBingo:
Met with Ryan, discussed the exploratory API server, set some work items, and moved forward from there. He now has access to the exploratory API server to review the code and explore it's configuration and operation. I have a few new work items that will take some time to knock out.
The afternoon activity (not dev related) took up a good amount more time than I expected. Good progress was made but I was pretty much done for the day after that. Goals for today now pushed forward into the week.
USMNT is out of the FIFA World Cup, oh well.
Did some more work on API Server experimentation. Some key takeaways:
MyModel.findOne({ name: 'Jon' }, function (err, myModel) {})
.const result = await MyModel.findOne({ name: 'Jon' }).exec()
.Update multiple documents across model namespaces in the same DB:
Model.findOne({}).exec()
for each input and store each result into a variable.myModel.save()
to store the least impactful document first (e.g. a child array or ancillary meta data item). If that fails, return an appropriate http status code and exit.I wasn't following these steps very carefully when developing a function that updated 2 documents with one API call, and it was tough to determine what the problems were when things weren't going as expected.
Commonly Used HTTP Status Codes:
Some more database lessons:
updated: DateTime
field to capture when a change was made to a document.deleted: Boolean
field to 'delete' a document. This can be helpful to ensure the ability to 'roll-back' a delete operation, either administratively, or via an end-user control (if the API allows it).deleted: Boolean
to track documents that are ready for actual deletion by an automated or otherwise triggered process during low activity levels or at certain other times.Findings about Server-side Cache:
request
properties (JSON, Body, Params, etc) isn't good enough because not all requests use the same payload mechanism.Goals for Tomorrow:
Meeting with Ryan:
Discovered MSFT Learning has beginner's videos about Java! Hosted by Brian Benz (@bbenz) and Mark Heckler (@mkheck) at Microsoft Learn - Java for Beginners.
Watched an episode of Azure Friday and took some notes. Not sure I completely understand what is going on here. Perhaps it would be worth looking in to and maybe applying to Lingo Bingo.
Completed some end-of-week tasks focused on accomplishments and improvements going forward.
In a CodeFellows channel, a member mentioned Advent of Code 2022, an 'advent calendar' of code challenges. I had put on my task list to take on a code challenge, technical-interview style, so I used that as fodder to do so. I failed the design portion miserably, but after opening a repl.it to work through the issues I realized my approach was not taking advantage of javascript's capabilities.
Some key takeaways:
String.replace(regex, replaceString)
can work wonders.String.split()
to easily transform a CSV of Strings into an array of arrays.for...
loops and instead use Array.forEach( item => n)
to work through each iteration.Array.map( item => n)
for situations where replacement of original array is necessary.These notes span both Weds and Thursday.
Explored Auth0's "APIs" feature. This could be helpful for enabling Auth0 to authorize access to parts of an SPA or Node app. For now I've backed-out of the settings and am moving on to other things.
For now, the authentication requirements are removed from my exploratory API server so I can concentrate on updating the schema models and get those working with the existing routes, web templates, and processing functions.
Some REST and CRUD takeaways from today's experiences:
/foo/:id
and the URL address will be https://foobar.org/foo/identity
. ExpressJS Request object will have 'identity' stored in the 'params' field.Mongoose/MongoDB:
Model.find(params).exec()
until something better is learned (promises and Mongoose Schema tricks).new mongoose.Schema({ things: { type: [String], } });
. This allows use of push()
on the field once the ref object is created to add items to the array (see documentation for examples of using $push
).IDs versus Hash Codes versus UUIDs:
const foo = buf.toString('hex');
General Coding and Design:
Interesting reference:
REST API Tutorial website breaks the REST verbs down into easily digestable chunks.
These are now done:
Worked through Ryan's latest PR and approved and merged it.
Continued API Server design efforts:
Completed goals:
The sign-in/out functionality is implemented but the Presenter User Stories paths haven't been fully implemented in the UI or in the routes. That will be a work in progress for a few more days.
Started adding models and middleware to the exploratory API Server:
Did some looking for apps that would create an animated gif, hopefully really small in file size, of the LingoBingo website. I settled on ScreenToGif because it is pretty simple and straightforward. It is a Windows app though, and it wasn't able to make small enough files to be hosted in our GH repo. There are some options for how to host an animated gif and link to it that I will have to explore. Turns out the project is built in CSharp and is open source (perhaps something to look further in to, in the future).
Authentiation - Auth0:
Goals:
-[X] Re-watch WDS episode, uninterrupted. -[X] Review LingoBingo Trello and work on at least 1 card. -[ ] Implement caching on the API server demo. -[ ] Implement a sign-in and sign-out functionality to the API server demo.
Middleware:
router.get('/:id', getMiddleware, (req, res) => { res.send(req.params.id)})
.app.use()
or router.use()
just-in-time before it is needed, so that code that does not need the middleware doesn't have access to it.Reviewed Azure Friday Episode: Azure Kubernetes VSCode Extension introduction. This short feature quickly overviewed creating, deploying, updating, monitoring, and managing a Node.js instance in an AKS (Azure Kubernetes Service) service.
Worked with Ryan here and there on the hamburger menu PR. Lots of progress made after a bunch of discussion. Somehow my local git got out of sync with the PR despite carefully pulling from the correct remote and PR branch. A quick clone to a new folder, git pull from remote PR branch, npm i, and npm start, and the code on my local was fixed. This is the 2nd time this has happened to me. I'll have to figure out how this keeps happening because it is causing interruptions in the dev and test processes.
I reviewed a Web Dev Simplified episode on quickly building an Express + Mongo API server. There are multiple good nuggets of information in there:
nodemon src/server.js
will explicitly call this functionality in an environment where env.Dev=true
.--save-dev
puts these modules in the 'devDependencies' section of package.json, rather than 'dependencies' section, so they are only loaded when env.Dev=true
.I'll need to watch it again and take better notes. There were too many interruptions to capture all there was to get.
Ryan and I met for several hours to go over design and architecture details of our next planned version. We refined some of the work items in Trello and moved lots of stuff into TODO. There is more architecture to get sorted out though:
Had pretty good success developing API server path(s) and using Pug for forms-based interaction with the API server, interfacing the Mongo DB:
Some things to consider when planning API Server development for LingoBingo:
Lots of learning new things today. Also, reminders of lessons from previous experiences. I'm not writing fabulous code out of the gate, but I'm pushing boundaries and getting further along building an API Server using my own resources. If I would have been asked "what is 'middleware' in ExpressJS" last week, I wouldn't have had much for an answer. Today this is different and I feel like this is something I can intelligently discuss with others now.
LingoBingo setup stuff:
Somehow I couldn't recall how to do object destructuring so I looked it up on MDN. Simple: { param1, param2, param3 } = inputObject
Back to Express, this time revisiting Forms, Jade, and Auth0. Will work on integrating with a database a little later.
Pug takeaways:
I posted an answer to a StackOverflow question that seemed to lack good answers, and it felt good to work through the problem, find a solution based on the original poster's code, and provide a structured, descriptive solution with a simple, tested code example. Hopefully it helps somebody. I had forgotten about being a StackOverflow member - probably because answers to questions are so common, and rarely is much additional information helpful (i.e. others that have answered have done a really good job). To update my profile, I added a slightly modified introductory statement, and inclduded a profile pic.
As I get ideas and find a few extra minutes, I will update Miro (and Trello) with LingoBingo JS features for v.next.
Express CRUD with Mongo Atlas takeaways (so far):
Continuing using express with postgresql from LogRocket blog. I was stuck on querying a single user by ID:
Some other takeaways from the ExpressJS + PostgreSQL exercise:
[ ]
around the variable to insert.module exports = { getUsers, getUser, addUser };
at the end of the file.LingoBingo MVP is live! Currently it is hosted on Netlify using built-in "ITU Phonetics" wordlist. We plan to set up the back end for the next version, and it will take some time to flesh out all the details.
While getting the computers set up for today, I ran across some older C# project files, mostly during and soon after Bellevue College classes a few years ago. So many exercises and some clever solutions to problems are hidden in there! I recall having difficulties dealing with Chars and Strings (conversions, slicing and splicing, and regex operations) during Code Fellows. This was very frustrating because I felt like I had solved those problems before, but I couldn't recall how to do it. Takeaways:
I'm realizing that using the same Express server to explore and develop multiple features is getting a little complicated, so this weekend the goal is to create new Express servers for each single or limited number of features. This will force me to review the setup and install and implementatin processes, which should be good exercise.
Started working through a Log Rocket blog post using express with postgresql in a separate Express instance to quickly connect to a relational DB instance. It has been a while since I've done this so some of it is a little awkward. Hopefully this experience will help me when LingoBingo moves into post-MVP development.
Reviewed current status of LingoBingo with Ryan. We have just a couple more work items to resolve and we are going to call MVP achieved! We will have more development sessions this weekend, most likely Sunday.
There were a few other tasks I had to complete today for my volunteer work. This slowed my progress with everythingn dev related, but at least those tasks are sorted out and I can move on.
While exploring Cookies in ExpressJS, I ran across a scenario that I haven't considered before: Using Pug/Jade templates to design a submittable Form. This led to an older blog post on 456Bereastreet.com that talks about including labels on forms for the sake of accessibility. Some key takeaways:
div
or fieldset
to wrap Form elements.Continuing on, I found that there were intracacies of Pug and ExpressJS's Request and Response API's that I either don't have a good grasp of, or have otherwise forgotten how to use effectively, so I will need to review some of my prior work and de-clutter my learning environment to make better progress.
This week has been very busy. Unfortunately not all of it was busy in the ways I wanted it to be.
Worked with Ryan intermittently to get these last few PR's reviewed and merged in, and locate other last-minute changes necessary to meet MVP. We will meet on Friday to discuss the state of things and next steps.
I spent some time updating my profile on LinkedIn, adding links and some descriptions of current projects, revamping my intro, and creating a tagline. I still need to rework the resume a little bit. As the LingoBingo project comes to be useable, I'll have to promote that a bit more.
Today I spent a couple hours with Kevin L to look at purchasing equipment for the volunteer team's operations. We had good conversation and find a lot of agreement on the approach to interoperating between the agency and the volunteer team. Most of the budgeted items for this year were purchased. There may be networking opportunitites here in the future.
Also today I worked through some interview preparation tasks including refining responses to behavioral questions, considering what I want in a 'dream job' team and organization, and thinking up important questions I want answered as part of the interviewing process. These activities are helping me gain confidence in my ability to have a relaxed, productive conversation where I can put myself in a good light, and also determine if the prospective employer is one I want to work for.
ExpressJS has been displaying a warning whenever I launch the server. The message is "using form_post for response_mode may cause issues for you logging in over http...". In a development server, without a self-signed certificate, http is the way to go. Production servers would (of course) use a signed cert and leverage https. Since the example server I'm working on leverages Auth0, they have steps for running https in development, which should resolve the warning by implementing a reverse proxy (they recommend caddy). When running expressjs behind a proxy, 'trust proxy' must be configured, otherwise expressjs will register the incorrect 'client ip'. See Express Behind Proxies documentation for details.
Spent lots of time working through LingoBingo PRs on my own and with Ryan. This was the focus for today.
Much of my day was spent working on volunteer work items, to clear the way for trainings, meetings, and exercises in 2023.
Completed a code challenge, whiteboard session only. It took 70 minutes to complete all facets:
Completed Graph write-up, implementation, and full suite of unit tests. There are a few minor lingering items that I could revisit in the future as a means to jog my memory on this data structure and the algorithms used to traverse it.
Sorry Friday, it wasn't your day.
The Lingo Bingo project continues to move forward, and we are marching ever closer to MVP launch!
Met with Ryan on Lingo Bingo project and made lots of progress reviewing the Trello board:
Reviewed an Azure Friday video on using Mongo and Cosmo DB via a local, virtualized developer instance of the services. Very cool!
Thursday:
Friday:
Meeting with Ryan about project Lingo Bingo has been rescheduled for Saturday 12-Nov.
GitHub Codespaces Sounds Interesting!
CSS Animations can be tricky:
overflow: hidden
to keep objects from expanding the view port size when they spill over.More DotNET Conference 2022 video viewings and note taking.
SVG and Playwright were mentioned.
Completed some tasks for LingoBingo and prepped a test deployment of the latest changes to Netlify. Many of the tweaks I am encountering seem much easier to approach and deal with than in the past. Progress!
Lastly, I spent some time tweaking the Screen Party animations:
DotNET Conference 2022 starts today. Notes will be stored elsewhere.
Between interesting DotNET Conference sessions I worked on java-code-challenges, implementing a Graph class and requisite unit tests.
Took some time out to respond to some interview questions before tackling Cheerio. It took much of the day to learn how to use Cheerio once I got an Express server running (which was key, really). Since I have been focusing on Express recently, I also reviewed the following packages since it was convenient to do so:
The one part of deploying Express that I didn't pay much attention to (but I should in the future) is using NPX vs NPM INIT and building by hand. The NPX initializer builds-out a deprecated templating library (Jade) and includes Express Router and lots of setup and sample files. This isn't a bad thing. In most cases though I think it would be good for me to build the server by hand and get more out of the experience.
Reviewing Express.js today:
Worked with Ryan on LingoBingo updates, PRs, code reviews... via GitHub, Email, and Slack. We are getting very close! He resolved several bugs and is moving things forward nicely.
While exploring Express.js and Auth0, I discovered Auth0 provides profile information for free. It's not a lot of info and really only includes the user name, locale, email, and an access grant token that is only used in the current authentication session. However, my exploratory Express server didn't have a way to display the data in a user friendly way.
Express.js and server-side HTML Key Takeaways:
#{variableName}
to pass-in data.compileFile(path/to/pugfile.pug)
and compiledFunction({ propertyName: variableName })
res.send()
, just stuff the compiledFunction into the send parameter.Express.js Social ID Providers and Developer Keys:
Survived the windstorm and power outages last night and this morning. Back to it!
Attended a webinar by a Code Fellows alumni and ex-instructor re: CSS. Was well worth the time, and he was very good at walking and talking through what he was doing and why.
Walked through the steps necessary to deploy React Apps to Netlify and Azure App Services. Netlify is pretty easy just on its own, and deploying to Azure App Service is made super simple using the Azure Extension for VSCode. 9/10 do recommend! For LingoBingo we will plan to deploy "production" front end to Netlify, and back end features (API, DB, Authentication and Authorization, etc) to Azure.
The local MongoDB installation needed to be removed from my main dev workstation, so that is now done. There were some Linux updates ready to install so I knocked those out too. After some additional research about Netlify vs. Azure App Service Web App. Before I do any more research, I need to deploy the LingoBingo website as-is to each and document the experience.
Next was to review Hash Tables. I keep forgetting about a few important Fields and Methods:
Pattern and Matcher classes:
String.replace(regex, String)
or String.replaceAll(regex, String)
which can be used to replace substrings within a larger string.Here's the suggested development pattern from Oracle Docs on Java:
Pattern pattern = Pattern.compile("\sword\s");
Matcher matcher = Pattern.matcher(Input_String);
boolean result = matcher.matches();
Finished off the Rotate 3x3 Matrix code challenge from yesterday. Added a feature where it would rotate other sizes including non-equal sized rows and columns, so long as the input matrix x and y are 3 or longer.
Walked through some documentation about deploying a server-side Node.js app to Azure. Documentation is pretty good and there is now a VS Code Extension (several actually) for Azure. It's worth noting that full Linux-based, Express.js server applications are supported, and MongoDB can be part of the Web App solution, too. This could work well for Lingo Bingo.
MongoDB (local installation) was not playing nice so troubleshooting and reinstallation consumed a bit of my time. It's funny that although Mongo Org has lots of great documentation, they are pushing pretty hard for users to just use Mongo Atlas...which is what I'm going to do for most projects going forward. I guess PostgreSQL will be the local DB platform for me? Maybe MySQL? We'll see.
Took some time out to attend a Microsoft Reactor presentation on Rust (of all things). Key takeaways:
I'm not at a point where learning a new language is a productive endeavour. It is good to take the pulse of the dev world.
Back to deployment options for Lingo Bingo:
I found a blog article that talks about using Netlify Serverless Functions to talk to a MongoDB Atlas cluster, rather than rely on a back-end API: Netlify Serverless Functions with Mongo DB. It wasn't terribly good, but I understand the jist of how it works, and the numerous gotchas and limitations. Not sure this is what we are looking for.
After some additional research on deploying our React Site and a possible API Server w/ DB Access, I changed gears and completed a 40 minute Code Challenge - rotate 3x3 matrix by 90 degrees. This went fairly well, although the final code had a major bug it in. Analyzing the solution, documenting take aways, writing unit tests, and implementing (and bug squashing) the code was a good exercise. I have updated the 'java-code-challenges' repository with commits from this effort.
Hard to believe it is November already. I took time out yesterday and today to brain-dump everything I thought I knew about Stacks, Queues, Linked Lists, Hash Tables, Graphs, Trees, and sorting algorithms. Sorting Algorithms is different in that recently not much time has been spent studying them. Given my experience with the other data structures and algorithms, I feel like it is a good time to take on a merge-sort algorithm and just see how far I can get on my own.
Key Takeaways - Problem Solving:
Key Takeaways - Java Coding:
List<T>
type to a []
type (e.g. int[]
) is to Ehanced For loop through the List and assign values one at a time to the destination Array, index by index.Saturday featured a communications exercise through early afternoon, and then family time for the rest of the day.
Sunday was a down-time day. I managed some documentation related to Saturday's post-exercise debriefing discussion, but largely it was an opportunity to decompress from a busy several weeks.
Today I had a late start and decided to work on yaml skills. My java-code-challenges repository in GitHub is a good candidate to explore yaml files and will benefit me in assuring builds build and tests are passing before merging into main. I've looked at YAML before and it had confused me (still does). Today I was able to make progress and defined 2 files: One for on push and another for on PR.
YAML key takeaways:
./github/workflows/
directory of the repo.Resources:
Attended a PPH Session today with a guy from Microsoft talking about his journey of 40 years in the tech industry, from C++ to Xamarin and C#, to Cloud Advocacy. Good session, enthusiastic guest, enlightening takeaways, and overall enjoyable. Turns out he has had a similar experience to mine, in having to leave a job due to a bad manager.
Spent some time reviewing Cheerio and the more I look at it, the more I wonder if this is something I want to get involved with. I will give it some more time, to see what it can do. Also, having some experience with it should help me gain the context necessary to help solve that (8 year old!) Issue they have sitting there.
Took some time out to sketch a REST and CRUD design for Lingo Bingo. This came to me relatively quickly including n-to-m relationships. We now have a draft outline of custom API server features, interactions with an external authentication service, a database service, and users based on authorization types.
Revisited ExpressJS to jumpstart my memory on how this all works. It's nice that it is such a small, simple thing, but there are a lot of libraries that can be bolted-on that make it (highly extensible and capable) difficult. Key takeaways so far:
npm init
, responding to multiple questions to create a default package.json file.git init
so changes can be reverted, committed, and pushed to a remote repo.npx express-generator
. This installs 'jade' as the default view engine (which will be deprecated from future versions and will require --view=jade
to put it back).npm install
. Should be gut-reaction at this point (but it's not).npm start
to run the Express server, regardless of exactly how you created it.npm start
. Instead, do npm install nodemon
and then execute nodemon
and when changes are detected, Express is restarted automatically so changes are 'picked up' right away.Last thing to note: Working server side is making me smile a lot. I am excited to move to this server-side portion of the project!
Today I spent most of the day working through some older assignments in the data structures and algorithms repo. Key takeaways:
I am celebrating my successess in updating these months-old projects.
Sometimes challenges are designed in a way that the candidate is very likely to fail. It doesn't matter if the wording is imprecise, wrong, or otherwise misleading. The idea behind code challenges is to determine:
Here's an example of how to frustrate your candidate and see how they deal with it:
At any rate, it was fun to solve the challenge a few different ways. There are at least 2 other ways to solve the challenge but I am not going to pursue those today. I am glad I have the brain dumps, code, tests, and analysis to review in the future as I see fit.
If I had an extra couple hours yesterday I would have completed implementing a CSS theme-selecting feature to Lingo Bingo earlier. This is exciting! I accomplished CSS magic with little help and lots of exploration and logically working through the problem on my own:
The idea to use a CSS Class selector came from css-tricks.com.
I reviewed my latest code challenge attempt and there are problems with the pseudocode and the slightly altered actual Java code:
We've been looking to find a font or three to use for the Lingo Bingo project. Some resources were added to the Trello board so I read the article about Roboto and took a peek at FontJoy to find some reasonable pairings. Will have to revisit this in the future with the goal of making a decision.
While researching hosting options for Lingo Bingo I found Azure to be a pretty capable. Looking at Heroku and Azure, it is clear that deploying a database server/service, storing the data, and dealing with transaction or request limits is much more expensive (and complex) than deploying a web app, desktop virtual machine, or some other services. Azure does have one benefit of having a pretty cheap SQL Server deployment tier that will consume some credits every month, but the capabilities of MS SQL are all there. It is possible that mutliple services will be used for example: Front-end webapp on Netlify and a back-end API with MongoDB in Azure.
More research is needed to review a few other hosting services to see what we might use, and what we should get ready for. RedHat OpenShift is so market-eeze that I can't tell what it might cost to use it, much less exactly what I'd use it for. Netlify is a known quantity, and as a front-end hosting platform it will only provide a part of the solution. Heroku has something called 'build packs' that support React, but are completely unknown (to me at this point). Heroku also has Add-Ons that will enable MongoDB access and other features, but my experience with those is they are supplied at a cost (although a minimal PostGresQL was available for Java-based deployments and was free, that doesn't help us in MERN-stack world).
I took some time out to look at Expressjs, since I haven't used it at all since May. It will take a minute to get back up to speed and I already have several other things to work on so I created a card to come back to exploring Expressjs in the near future, to support upcoming Lingo Bingo develoment tasks.
Dedicated a good portion of today working on Lingo Bingo. Ryan addressed the issue with the React-hooks which is great because I couldn't quite get it done. Instead, most of the day was spent working through theming issues. I still don't quite have what I want. At least there is a colorful, and styled website now that we can work with and is less... sterile.
Tomorrow I need to look at hosting options. Ryan had some feedback earlier today and I want to participate in the information gathering and decision making process. Looking forward to that.
Re-attempted a technical interview challenge see previous attempt notes below. I managed to complete all of the technical aspects of the challenge and came up with a sensible solution, but it took me 2.5 hours to do. A vast majority of that time was breaking down the problem in such a way that I could visualize a solution, as well as vocally and visually walk through solving the problem, before I could write pseudocode and actual Java code.
Key takeaways:
Turned my attention to LingoBingo for a bit to work out some theming issue. I don't quite have my head wrapped around this yet, but I feel like it is close.
Took some time out to do a technical interview practice challenge. Key takeaways:
Completed 2 behavioral questions. There are just a few more that I need to write out responses to, then I can start a serious review and better prepare for interviewing.
Attended a presentation session on web accessibility. I was aware there are standards out there providing guidance to make sites, services, products, and software accessible, but I wasn't aware just how far along those resources have come. Check out the W3C for details about the WCAG (Web Content Accessibility Guidelines) at all stages during the software development process. Doing so will bring the site/service/product closer to compliance, but the main point is to design for inclusivity.
Saw presentations by Javascript Full Stack developers and they were using a package called inquirer. It is a command-line interface for Node.js. They were using it to administratively update database entries, and manage services running on their backend infrastructures. This could be useful in future Node and Express projects! Turns out the class was instructed to do their projects without any graphical user interface at all, and use AWS Services for CRUD, authentication and authorization, and build custom API servers to manage their data calls. They all did really well!
Went through the java-code-challenges repository to review properties, methods, traversals, and algorithmic complexities. There were a couple of errors, some points that needed refinement, and some reference links that needed to be updated, so I did that. Having that repository with all of the documentation included seems to be a good idea as I am able to easily review the information and refresh it in my mind. This actually raises my interest in coding, so it might be good to do these reviews earlier in the day so I can take advantage of that coding desire.
Continued research using React Hooks. Much of the documentation introduces the concept of Context and 'useContext' all in the same file. That's fine except those examples fail to demonstrate leveraging a defined context across files in a React hierarchy.
Key Takeaways:
createContext(null)
and exports {MyContext}
.<MyContext.Provider value={myValue}>
.useContext(MyContext)
.Checkout this post on react usecontext hook by 'rw;eruch' aka Robin Wieruch.
Once I had spent a few hours with 'useContext' hook to get the hang of it, I took some time to work through some more CSS issues. Turns out there are areas where CSS and Bootstrap styling could be refined to make the GameBoard display more appealing. Right now it is a little weird in how the Tiles are sized and shaped, but the benefit of the CSS layout and using Bootstrap is the site is responsive to both desktop-sized and phone-sized screens.
I attended the Bellingham Codes Software Forum, where plenty of good discussion around building websites using React and javascript, among other things. Afterwards, I had more good discussion with Ryan, another attendee, about navigating becoming a software developer.
Some takeaways from the Software Forum discussions:
Researching Theming in React has tough. There are several articles that are very out-of-date, using older React techniques, are too vague for new developers, or the backing "see my github repo for the code" doesn't actually exist.
What I did learn is using React Hooks is a thing, and it could be helpful in creating themes for a React website. I started documenting some react hook takeaways for reference.
React Hooks uses concepts that are pretty familiar, now that I am gaining a basic understanding of the design patterns of Hooks:
About 'Array.prototype.reduce()':
// from mdn.org Array.prototype.reduce() documentation
const array1 - [1, 2, 3, 4];
const initialValue = 0;
const sumWithInitial = array1.reduce(
(previousValue, currentValue) => previousValue + currentValue, initialValue
);
Step Through:
Finished CSS cleanup from yesterday and built upon that by submitting a new PR to the Lingo Bingo project. Some display bugs were solved and general rules like avoiding in-line CSS and using classes or Bootstrap were implemented. The project is looking better!
Next step is to finish working on devloping a theme for the color scheme. For now the effort might be overkill, but in the long run it will simplify implementing alternate themes, and perhaps user-configurable ones. Not an official feature right now but will be good experience to have.
Took a little bit of a break over the weekend. Some development and exploration was done, but not at the level of the previous month.
Put some effort into learning CSS Variable usage:
:root {}
--rgba-primary-0: rgba(36, 69, 146, 1);
color: var(--rgba-primary-0);
I'm thinking there is probably a more robust way to implement this to simplify applying a theme to an entire webapp. Looking more into this subject, I started to see some style issues in the Lingo Bingo project, so I worked on fixing those. Some key takeaways recorded on Sunday September 3rd.
I also watched a video where a guy developed a javascript version of the Minesweeper game. It only took him 55 minutes (of video time) to get the core elements of the game working, including a UI. He jumped back and forth between whiteboarding and coding, so it was interesting and inspirational!
Attempted a code challenge "convert integers into roman numerals". This was very difficult and I ended with a partial algorithm and will need to attempt it again.
Attended a seminar on DevOps and AWS. Was very interesting and help re-kindle my interest in working with AWS, like in the Java 401 class.
Key takeaways:
Tailwind CSS was mentioned again with lots of positive feedback and kudos. I have that on my list of things to investigate.
Ryan and I updated some Lingo Bingo code and some PR's were merged in. So I moved forward with the "screen party" feature implementation. So far the integration of planned code into the gameboard was not too difficult. There is more work to do in the next few days to make it more awesome!
As of right now, I have a streak of a solid month of contributing code to GitHub. Some of that is due to my endless typing in this retrospective markdown, however there are definitely some significant code updates and project completions:
I took a look at a few blog articles about theming, and it is pretty invovled. It might be worth the time to look for a package that will manage theming and end-user-selectable theming. Until then, a baseline theme using CSS will be implemented, and I will consider what to do about theming longer term.
Monitored MS Ignite sessions again today. Notes are stored at MSIgnite 2022 Notes.
MSFT has done a lot of work to enable remote development, and IT management of remote development resources, via the Azure cloud. Although it is very Visual Studio-centric, they did demostrate Maui features (cross-platform build, hot-reload, and an android emulator).
I completed a React-Tac-Toe challenge: Highlight Winning Tiles. I updated the blargh article where the challenges are listed. Takeaways:
Array.prototype.includes()
.
Watching Microsoft Ignite 2022 this morning, looking forward to hear what is next from Microsoft.
GitHub Universe is set for November 9th and 10th 2022.
Git tid-bit:
git commit -c {id}
allows updating a commit message for a commit with id.
What is an OKR? Objective and Key Result. OKRs enable setting and communicatingn goals and milestones.
During the break in MS Ignite sessions I worked on LingoBingojs. I updated information on a PR so that my partner could make some tweaks and the PR could be incorporated to main. We're getting pretty close to first MVP!
Quite by accident I bumped into cheeriojs/cheerio, an open source project that scrapes web pages and returns a tight, scaled-down DOM. ikatyang's emoji cheat sheet utilizes cheerio to create the list. Turns out there is a 'good first issue' item in the Cheeriojs repository, so I forked it for future inspection. This could be a good next opportunity to contribute to the OSS world.
Back to MS Ignite, David Fowler and Damian Edwards shared some interesting ASP.Net 6 and DotNET 7 preview code and features. In the past, these sessions have been difficult to track, but with Code Fellows training in full-stack web development, the terminology and features they discussed were consumable and interesting.
Another poster added a link to Jake Archibald's blog page that discusses CORS in historic detail. It's also pretty humorous. Key takeaways are stored in cors-review. Key takeaways for right here:
Vary: Cookie
and Vary: Origin
to ensure caches do not send aged response instead of fresh one.Access-Control-Allow-Origin: *
.Seems like using this.setState((prevStat) => {})
will alter the developer's approach to updating State under certain circumstances. For example, if a collection of items is already a property of State, and another property changes based on that collection, then updating the second property will not be possible in a single setState call.
Some resources to review:
Turns out the work around is to just call this.setState({ item: {value based on otherStateItem ,}})
and it will work. My gut sense tells me that there are probably better ways to manage state than this, but I don't have concrete evidence to support it.
Many tests I wrote for the project were using lots of .forEach()
statements and creating lots of arrays to store JSON data. Ryan suggested moving to a more object-oriented approach so I refactored the Jest files. While doing that I realized he could have meant doing something a little different, so I posted what I did and asked him for feedback. In any case, I learned:
.find(arg=>arg.property===testSubject).property
.Using '.find()' makes the code a litte bit longer horizontally, but from a readabilty perspective it is pretty good, and it hides the ugly iteration detail.
Reviewed some of Ryan's code for the LingoBingo project. He's working on a play again button, so I reviewed the code, pulled in his changes and ran them, and sent him some feedback. That functionality will definitely be needed but it's not fully baked yet.
On Friday I experienced some anxiety figuring out why some of my Jest Tests were failing, and others would appear to hang. There are key takeaways for Friday that cover most of the items but there was one remaining question: Do Jest Tests run in parallel? Behavior of npm test
output and the errors I was seeing suggested that was the case, and today I verified it with some internet searching. According to www.oreilly.com and GitHub Facebook Jest issue 5818. A read through provided some detail on how Jest operates.
Key takeaway on Jest parallelism:
Assume Jest will run your tests in parallel. It might not, but unexpected side-effects will happen when assuming otherwise.
After integrating my calculation components into the Lingo Bingo React project, it became clear that one of them needed to carry more weight, and provide better output, so I refactored it. This meant that the Jest tests had to be updated. This work is incomplete as of the end of tonight, so I'll pick it up tomorrow. Takeaways?
Today I worked through writing the basics of a Graph Data Structure, and the traversal algorithms. I found an interesting slide deck for a computer science class at the UW CSE 417: Algorithms and Computational Complexity that was helpful. It had an interesting quote from Walter Ruzzo, Professor of Computer Science & Engineering and Adjunct Professor at the University of Washington.
"Never write an argument you are not convinced in because this may damage your brain." [Ruzzo]
Some key takeaways:
There are a couple of presentations I want to attend early this afternoon.
First was refactoring: How and why. In essence, code smells will appear for many reasons, and it is important to try and refactor code to remove the code smells, making it more easily readable, less prone to bugs, and better performing.
Started working through Lingo Bingo logic to determine when a Bingo has been attained. This will be in a dev branch and can get refactored and reworked as necessary.
Key Takeaways:
.map()
and .forEach()
to push data into an Array explicitly so there are no assumptions about A) the data getting added to the array, and B) the number of items the array will contain.Bitmap Transformer Project: It took a bit longer than I thought it would, but I completed this project today! While writing up method descriptions I realized many methods were too busy, and some basic checks were not being done at all, or not very well. Also, while writing unit tests I realized there was some logical processing flow that didn't make sense, so some refactoring had to be done.
Key Takeaways:
Behavioral questions: I addressed two of these today. One was a revisit, the other was one I hadn't responded to before.
Working through some Java concepts in ReplIt, I discovered that replit isn't really a great place to sandbox Java code. It seems to be unaware of basic Java libraries like Pattern and Matcher classes. So instead I spent a little time fiddling with JS arrow functions.
Key Takeaways about Arrow Functions:
const result = (params) => { codeBlock; return value; }
.result(myParam)
.An example of what I threw together can be found on ReplIt.
At this point I've deployed a new React website a few times. If from here-on-out I continue doing React Web Dev, I'm sure it wouldn't be an issue to know how to deploy a new React site, or add React to an existing one. However, right now I have many different tasks on my self-assigned plate, from web dev, to Java dev, to software design, project management, and algorithm studies. This makes it difficult to be an expert in any one area, and I recognize the power of knowing React and web development so it is important to have some key takeaways to look back on.
React Deployment Key Takeaways:
npx create-react-app {project-name}
. CD to 'project-name' => Default React site with Git already initialized.npx new-react-app {project-name}
but that is a bit different.npm install
or specify: npm install {module-name module2-name ...}
npm start
npm run build
npm test
manifest.json
and make edits only as necessary.The Syntax podcast mentioned CORS and CORS-related issues, so I took some notes. This lead to writing a new article about CORS so I could easily reference it later. This could help helpful on future web projects such as LingoBingo and other project ideas I have.
My attempt at a 40-minute technical interview challenge ended with timer expired before I could finish writing java code. Completing the code, then writing about testing approach, and of course Big-O were necessary to ensure points capture. Later, this item will be added to the Java Code Challenges repository (just like the others) and must be re-attempted at a later date.
Since I had a little time before lunch, I responded to a few sample behavioral questions. These are slowly getting easier to respond to. I feel like they are less burdensome, and more like an opportunity to share my story of who I am and what I can do for a potential employer.
Back to CSS Animations:
@keyframes
, or a combination of @keyframes
and animation-timing-function
.To experiment with CSS Animations, I created a ReplIt called React Css Animations.
Before the day ended implemented the technical interview challenge in my Java Code Challenges repo. My pseudocode solution really wasn't all bad, but it was lacking some simple bad-input checks. I still have a question about whether in a Kary Tree if checking across a "holey children array" could produce a Null Pointer Exception. I don't believe it would. That is something I'll have to explore some other time. The final solution, with a Kary Tree anyway, is all completed, unit tested, analyzed, documented, and checked-in now. Code implementation was pretty fast and very few lines, so I must have done something right.
Back to the bitmap transformer project! Had I taken time to look into BufferedImage class back when I first did this assignment, I probably would have been able to complete it, or at least get one transform done (instead of none). Key takeaways:
write()
method => bmp is not supported. To get around write, write a PNG file instead.If I ever want to show some regex skills, I'll need to become more familiar with Pattern and Matcher classes in Java.
Multi-use:
String inputParam = "I contain letters and spaces.";
String regex = "[a-zA-Z]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(inputParam);
boolean result = matcher.matches();
Single-use:
boolean result = Pattern.matches(regex, inputParam);
Note: The Oracle Java docs have a special set of REGEX rules that are slightly different than what I've seen elsewhere (e.g. regex101).
Responded to a behavioral interview question. This was in interesting one because it is basically asking what gets me exciting about software development. The basic answer is: solving problems, and watching unit tests pass, proving the problem is solved. There is more of course, but that is in the details of the answer I drew up and will refine.
Final set of takeaways:
Last couple TODOs for the bitmap-transform project were completed on October 6th:
While I was checking in to a couple of ham radio nets, I decided to take a peek at the NWS API. Key takeaways:
I added some comments to my "Practice Boards" in Miro, as well as some added Cards and details to Trello for future projects based on using NWS API.
That will be it for this very productive day!
Updated the Trello and Whiteboard documentation for the LingoBingo project with ideas sparked from yesterday's conversation, and whatever occurred to me overnight.
In one of the forums I follow, a user is asking if folks are interested in learning about Streams...which is on my list of things to do, so that could be a nice additional resource!
Back to LingoBingo, I added a 'session' component that is used to get data and prep it for a gameboard to consume. The gameboard handles the display and click event and no longer has to manage importing the word data. This fixes a problem where clicking on the gameboard would reload all words.
We are going to have to figure out how to manage "Host" users vs. "Player" users. There is no decision on this just yet. A couple of ideas on how we could approach it:
Key takeaway: Trust myself a little more when it comes to solving problems related to React State.
Code Challenges: I discovered that my solution to "Is Anagram" challenge was not quite right. Turns out the input was to be 2 strings and the comparison is whether they are anagrams of each other. I might take on the challenge of fixing that in the near future.
I attacked another React Challenge: Add a toggle button that lets you sort the moves in either ascending or descending order. See entries from about 2 weeks ago for the full list and images of results.
Key takeaways:
.reverse()
method after using the spread operator [...arr]
on existing items.!this.state.sortAscending,
.onClick={()=>this.toggleDescending()}
.On to Java Code Challenges! Reviewing the isAnagram solution, it turns out I solved the palindrome problem instead of the anagram one. Granted, a palindrome is an anagram, there are a bunch of use cases that won't get solved by the isAnagram method I created. So I completed an update to the java code challenges repository that addresses that problem. There are now two classes - one for the Palindrome problem, another for the Anagram problem.
Takeaways:
Also, when thinking about using Hash Table, recall that it:
That's it for today.
Met with my project cohort and reviewed the Trello board work items, updating and closing a few of them. There is a lingering issue of the full-page refresh when State is updated. Normally that wouldn't be a problem except the refresh causes the words to randomize again, which is a bug. We think that changing the location where the wordlist is imported and randomized will fix the problem, so I'll work on that and see what I can come up with. Ideas:
I spent some time figuring out how to install, configure, and utilize Jest. It's not that difficult really. Some key takeaways:
isStrictlyEquals()
chained method.Jest supports:
I set up Jest on the Lingo Bingo project and submitted a PR with a couple of test files pointing to the purely functional modules. From here on out, it would be good to get unit tests written to any new PFM's, or any updates to existing ones.
This morning I attempted another technical interview question and could not get code on the board before 40 minutes was up. I believe the overall design is close, but there is definitely a problem with the iterators and indexing. Using a Stack seems like a great idea though.
Key takeaways:
throws
keyword.Object
. Yes, un/boxing and various Casting calls will be necessary, but this will allow developing the solution rapidly, without getting hung up with Generics.Character.toLowerCase(char)
but it is a little different than String string = character.toString()
followed by string.toLowerCase(Locale.ROOT)
. This might be worth reviewing a few times to get the hang of.This afternoon was a presentation by a Code Fellows alum and previously an instructor. She discussed the importance of, and how to work with, ambiguity.
Key Takeaways:
Ask questions to:
Well, that's time for today. Many other tasks stood-by while I got this sorted out, however these challenges are forcing me to break-down problems into very small parts, and think through solving each step in a sensible way. Back at it tomorrow!
I started today completing some housekeeping tasks - literally - so no technical work or exercises were completed this morning. At least the house and yard are a tidied up a bit.
Back to the Java Code Challenge: Browser Navigation History. I completed designing, implementing, and testing enhanced versions of Go, Forward, and Back methods. Confusing elements:
Chrome://history
! Figuring out which to follow (and why) caused me to develop 2 solutions to the code challenge.In retrospect:
There are a bunch of tasks now in my Trello board, one of them I haven't touched for several weeks: Java Project 'bitmap-transformer'. I'll take a peek at it and try to knock out something small before the day gets away from me.
First things first: Can I build it? No, not with gradlew...and a few adjustments.
gradlew
-> Command on found!./
to prefix files in the current path../gradlew
permission denied!sudo chmod +x ./gradlew
.git update-index --chmod=+x gradlew
but that didn't seem to work - perhaps it needs the prefix for current directory also.It took a while but I started to figure out how the ImageBuffer class works, and the RGB / ARGB properties are handled internally. So I refactored and added to the existing code. Good news is it doesn't crash, and the arguments input to the App are accepted. Next step is to debug and find out why the output file is not written to disk. After that, find out if the image is changed at all, and if not, why not.
But that will wait until tomorrow.
There are never enough hours in a day:
Of course this is nothing new.
This morning I knocked out a couple behavioral questions. One of them was asking what I aim to accomplish in my first 30, 60, and 90 days on a new team. Generally speaking there are things I can talk about. Without knowing anything about a company or team or code base, the answers are going to be fairly unrealitice -- although the general concepts around what is important as a new dev on a team should be well orientated. This speaks to actively reseraching companies I am interested in. Soon I will need to return to doing this as I am increasingly excited about my next big thing and look forward to getting underway!
As for the Browser Navigation History challenge in my Java-Code-Challenges repo, I decided to approach implementation from a test driven development perspective. Although I already have the algorithm written, the code is not. As I write the code I want to be able to run the tests and modify the code to make the tests pass. I made a good amount of progress and discovered that there are a couple ways to implement solutions to this challenge. Once I was done writing and testing the algorithm I designed in Miro, I started planning an "enhanced" version of the methods that would solve the problem, matching the behavior of "Chrome History" a little more closely. It will take me into tomorrow to finish designing, implementing, and testing that code.
First stop was to pick-up where I left off with CSS Animations. I have a video from Web Dev Simplified to watch, some more experimentation in the sandbox Reactjs site to do, and some emojis and/or thumbnail images to make.
I completed a couple behavioral questions and am starting to think I need to re-think how I respond to these so that when the time comes, I have realistic answers to use with tie-ins to who and how I am.
Code challenge: Haven't quite got there yet!
CSS Animations: I updated my current exploratory ReactJS project and things are working with images and emojis. So far so good! Repl-it has a React template now, so I refactored the code into that environment and it works, so I'm doing something right.
I spent a little extra time exploring Hashtables to wrap my brain around the expectations of these technical interview questions. I'm pretty sure I have the technical aspects of these data structures. The issue is probably two things:
The impetus for that second point come from reading my README file about Hashtables and the Repeated Word challenge, and one of my takeaways from yesters: Don't waste time implementing those 'already implemented' structures and instead use an existing language library. Given the 1st point above, I should be able to talk my way through what I would be using, why, and how.
So I attempted a new 40 minute code challenge and time expired before I could complete writing Java code. I did manage to write out the problem domain, review inputs and outputs, depict the problem and step through it for 1 test case, write an Algorithm, supply information on my test approach, and perform Big-O analysis on the Algorithm. I'll do further analysis at a later time and code up the correct solution in my Java Code Challenges repository soon.
Since today is coming to a close, I updated my Trello board and noticed I was missing a few things. So I added key tasks and aspirational activities that were already on my mind and one of them (Bitmap Transformer project) that wasn't listed at all. This way I can better track my todos, and 'imdones'.
Today I started out working on a technical interview challenge question. This time the question was to make a function that accepted a String as input, and returned true if all the characters in the input string were unique. This time I was unable to complete all of the Code Fellows grading rubric items within 40 minutes, but that's ok. I was on the right track, implementing a method that uses a hashtable. Had I not spent so much time writing out the hashtable functionality during design time, I probably would have completed coding and a step through. Commonly, I pick the wrong level of detail (usually too much) for situations like these, and that is what happened this time. Another issue was I couldn't remember how Java's String methods were used to a) replace characters, and b) split a String into a character array. After the time was up, I opened up a new brach on my java-code-challenges repo and built-up the solution starting with my whiteboard notes, and going from there. Within about 2 hours I had a working solution, fully documented, with a full suite of unit tests.
Takeaways:
A detailed readme with code analysis and links to the code and unit tests can be found in the java-code-challenges repo.
Next up was behavioral questions practice. This really didn't take very long and I probably should have done 1 or 2 more, but there was an event coming up.
The event was an Ops-301 final presentation. The students did really well, and it was interesting to see how they were solving problems like securing a network and wifi connectivity using VPNs, a capture portal, and AAA at the perimeter.
Following that, I returned to CSS Animations. The goal is to learn how to make an animated "celebration" happen on a web page under certain conditions. I'm going to need several things:
@keyframes
and animation
properties in CSS.I made a little progress by deploying a new ReactJS website to use as the experimentation sandbox. More to do tomorrow.
In my collaborative project 'LingoBingo js', there is a need to design an animation that happens when a user gets a Bingo. This is going to be a design challenge for me, since that is not my forte'. So to warm-up to the idea, I opened up cssbattle.dev, battle number 2, item 17. The image is somewhat complex:
Key takeaways:
::before
and ::after
pseudo elements because I could use the existing div without battling z-index problems.::before
element, caused other elements to move, as if they are all relatively positioned to one-another. This was difficult.position: absolute;
and transform: translate(x,y)
instead, which made it much easier to edit each pseudo element directly, without moving other elements around.display: inline-block;
but changed it to display: block;
. Inline-block seemed to artificially move the pseudo-elements vs. using block, which seemed to place the pseudo elements in a way I felt was expected.Next I completed CSS Battle 2 Challenge 18 "Matrix", earning 600 pts for a 100% match... but it took 834 characters to do it. It makes me wonder:
My initial idea was to use Divs with the ::before
and ::after
pseudo elements again, but I was concerned that I couldn't leverage property inheritance that way (may I can and I don't know it?).
I stuck with Divs and used a class hierarchy to identify the 2 colored shapes, each column, and each row. I then applied position: absolute
, transform: translateX()
, and margin-top (for Y translation) to position every div specifically.
To Dos:
One more challenge before I quit: Battle 3, 19 Cube. This was really tough!
Key Takeaways:
transform: translate(px,px) rotate(deg);
.transform: skewx(deg);
came to the rescue.I'm still not entirely sure I know the size of the center diamond shape, so it is extremely difficult to get the positioning right!
Nevertheless, I did complete it with a 99.9% match, 598 character score! That's pretty good considering how little I have used rotate and skewx/skewy properties.
For the last several weeks I have wanted to work on my desk a bit. There are USB and audio extensions that were just hanging around on and about the desktop and it was... messy. So I took apart the dual-monitor mounting system, added the USB + Audio line housing to the foot of the mount, and put the system back together. While I was behind the desk I added a second power stick to shore-up power cables to the monitors and a few other things, and cleaned-up the USB, audio, and D-port cabling so everything is nice and tidy now. My Uplift desk is so good.
I attended a seminar by Mica Goebig, where she discussed confidence issues, as well as managing fear and self-doubt. Her business is geared towards women, poc, etc. Her advice in this session was easily transportable to just about anybody. My takeaways to boosting my confidence are:
This afternoon I put some time into the Lingo Bingo JS. Although development has slowed, I am completing tasks one-by-one, successfully, and things are coming together. Some things that went well:
Some things that need improvement:
Back to React! Some key takeaways when developing a site that requires some initial processing to display a page:
render() {}
function.map()
or filter()
function to get what you do need.On another topic, some of my Code Fellows student-friends are at their 401-level finals week. I won't be able to see it live but I'm looking forward to seeing a video of what they did!
Worked on React again. Had some difficulty figuring out how to pull-in data, process it, and then set it into state. When setting State the Component reloads, causing timing issues. I should have been concentrating on passing functions as props anyway (that was more the goal), and handling the input data properly to begin with. In a future revision of this project, there will be a back-end API server that will manage gathering the correct data, processing it, and returning a data set that can then be set into State.
Code Fellows held a Code 401 Instructor's Forum this afternoon. These are always fun, and are chock full of reminders about what the classes have to offer (and what I learned taking Java 401!). Also, the banter between the instructors is pretty good. Someone usually has a good tid-bit about the industry, new hot frameworks, or tips around contracting or freelancing.
Speaking of which: I'm interesting in learning a little bit about Tailwind C S S. This has been added to my list of things I want to learn more about.
Lastly, I worked through a couple behavioral questions this morning. It is getting easier to write these. I need to remember to speak these responses out loud so I get used to hearing the question asked, and hearing myself respond. During several of the Code Fellows class sessions, it was pointed out that having ready-to-go responses to many behavioral questions is good preparation for interviewing. The practice helps to releive anxiety, and makes for a more natural, relaxed, and focus response.
No code challenges nor technical interview practice sessions were done this week, and it isn't likely I will get to them before this weekend. The plan is to get back to knocking out 1 of everything every day as much as is possible. Keeping a busy schedule with productive, impactful tasks will help me in the in the long run.
React challenges, continued!
I completed the challenge of making the currently selected move text bold (see the checklist below for a screen snip). The code was fairly easy, but it requires an understanding of the backing State and data, and also an ability to leverage boolean logic to select and apply CSS to an element.
<button
onClick={() => this.jumpTo(move)}
className={this.state.stepNumber === move ? 'selectedBold' : ''}
>
{desc}
</button>
.selectedBold {
font-weight: 700;
}
The next challenge proved to be much more difficult, but I finally figured it out. The Board component had a hard-coded render statement that explicitly set the row element and each "tile" element, and the challenge was to convert that into a pair of loops that would generate the tiles on the fly, instead. Scroll down to see the challenges and the solutions.
In summary:
map()
or forEach()
to prepare data for rendering in the render()
function.key={}
to functions renderSquare()
and setRows()
. renderSquare(i) {
return (
<Square
value={this.props.squares[i]}
onClick={() => this.props.onClick(i)}
key={i}
/>
);
}
setRows() {
const rows = [];
for (let rowId=0; rowId<3; rowId++){
rows.push(
<div className="board-row" key={rowId}>{this.setTiles(rowId)}</div>
)
}
return rows;
}
Reviewing React facts and usage this morning, here are some key takeaways:
super()
when defining the constructor of a subclass.Array.map()
, assign a proper key to each item. It only needs to be unique between Components and their siblings.key
items in State; they are used internally by React. Simply assign them in your code i.e. using map()
and move along.setState{}
to replace them. Calling slice()
is a good method for copying an array from State. The spread operator ...
will also work to copy Arrays and Objects from State.setState{}
is called, only the items specified within the braces are changed in State, the rest remain unchanged.concat()
because it does not mutuate the original array. This makes it compatible with State operations.Arrow Function used for an onClick event: onClick={() => this.setState({value: 'X'})}
Passing a function via props:
// in the parent class
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
}
// in the parent class render statement
<MyComponent
onClick={() => this.handleClick(i)}
/>
// inside MyComponent
<Button
onClick={props.onClick}
>Click me</Button>
Here is a neat little React js tutorial, and at the end some code challenges are posed. I started working through these because I was feeling like I was a little too rusty with React to make effective progress on the Enigma Bay project.
[x] Display the location for each move in the format (col, row) in the move history list. This took a minute to sort out where the data needed to be added, but once I realized the index of the clicked Square was maintained in the callback, and the coordinates needed to be tied to move history, I figured it out.
[x] Bold the currently selected item in the move list.
[x] Rewrite Board to use two loops to make the squares instead of hardcoding them.
[x] Add a toggle button that lets you sort the moves in either ascending or descending order.
>
Put some effort into the javascript project today. Some key takeaways follow.
React:
// import statements
import PropTypes from 'prop-types';
export default function MyFunction(props) {
return <div className={props.styleclass}>{props.message}</div>;
}
MyFunction.propTypes = {
styleclass: PropTypes.string,
message: PropTypes.string,
};
React State and Lifecycle, react-js documents
Components and Props, react-js documents
Type checking with PropTypes, react-js documents
Bootstrap:
Color customizations and theme system, from getbootstrap.com
CSS:
display: flex
? Then remember to also set 'height', 'align-items', and 'justify-content' in the parent container to make your life easy arranging content in the child box.:root {
/* selects all elements */
--primary-main-color: #12ae55;
--secondary-main-color: #0055ff;
--shadow-color: #112233;
}
To use these variable colors just call them using the 'var(--named-variable)'.
element {
color: var(--primary-main-color);
}
Using variables in css from MDN web docs
Wow did this week go by quickly, I can't believe it's friday already! Earlier this week I tackled another Java Code Challenge. It actually tackled me, so I had to do some research and due-dilligence to figure it out. Essentially the problem was I did not identify the correct data structure, or rather I picked the correct data structure but for the wrong reason and so I couldn't determine how to utilize it within the time limit.
The challenge is basically this: You are given a book's worth of text, and you must write a function that processes that String input to return the most commonly encountered word (the first one if there are many).
For example: Input <= "The quick brown fox jumped over the lazy grey cat."; Output => "the".
There are probably 2 or 3 really wrong ways to solve this problem that are inefficient, difficult to code, and probably hard to test. The correct solution involves using a hashtable. Where I got stuck was determining exactly how the hashtable could help me get the right answer. I wrote a custom hashtable with a custom Linked List as Buckets to help solve this problem, but had to sleep on it to come to a legical, working solution.
So this experience spills-over into Saturday and Sunday, delaying work on other things I really wanted to do, but this is important if I ever want to be an effective software developer.
Key takeaways:
More takeaways, about hashtables in general:
isEmpty() == true
upon hashtable instantiation.Administrative Stuff:
I added an entry to the Linux learnings documentation - how to keep MAN output in the terminal scrollback. While I was in there I cleaned up a bunch of text formatting that was just terrible. Not a great use of time I suppose, but it was a nice change of gear from code challenge solving, code planning and writing, and brain-dumping during and after.
Multiple other tasks consumed quite a bit of my day, and I managed to do some studying for interviewing, as well as knock out a code challenge session.
The code challenge was to find the most common word "in a book". The input would be a String containing lots of words, punctuation, and spaces. This detailed analysis was lacking in my 40-minute time-limited exercise, which slowed my progress. It was pretty clear that I needed to use some sort of Collection that would help me determine duplicate items, but I didn't quite get the right selection. If I had walked through the data structure and how it is traversed, I would have discovered helpful facts that I could have used in designing a solving algorithm.
When approaching code challenges, I need to remember to:
Continuing with the Java code challenges, I completed working on the core functionality of the Tree libraries. The K-Ary Tree was challening enough, and once I figured out to just stick with making "a tree of nodes" rather than a specific tree Class things got a lot easier.
I bumped into an interesting reference for using Java Generics at codejava.net called 18 Java Collections and Generics Best Practices. Although many points did not apply to what I was working on a the time, it looks like there is plenty to study and work toward understanding in the future:
Check out the site for details.
I've already implemented a few of these, and am working toward using generic Types more often and handling unchecked warnings (rather than ignoring or avoiding them).
I could use more practice with generic methods and lambda expressions with forEach(), but I'm pretty regularly using the diamond operator and Enhanced For and While iterating structures.
The Stream API is still a dark art and I just need to gain some experience with it and I should be able to grok it.
When developing in C-sharp, I tend to implement Equals() and HashCode() overrides, but in Java I have not been doing so (and I could stand to do so for the exercise).
As I learn more about these best practices and start implementing them, I'm sure I have more notes and comments to make here and elsewhere.
While working through the Binary Search Tree Node class, I realized there was still a challenge ahead with recursive functions if I wanted to use them. Because recursive functions pop-off the Call Stack automatically when they exit, any of their data also disappears, never to be seen again. Passing data between recursive calls is possible, but tricky. But I wanted to be able to return an in-order list of values within a BST, so I had to figure this out.
Key takeaways:
this.storage
(or whatever it is named at the Class level) and add (or otherwise append) to it from the recursive call.this.storage
to get the data the recursive function outputs.Working code:
public class MyNodeClass {
// fields
private List<Integer> values;
// methods getLeft(), getRight(), and .getValue()
private boolean inOrderTraversal(MyNodeClass root) {
if (root.getLeft() != null) {
inOrderTraversal(root.getLeft());
}
// process root node here
this.values.add(root.getValue());
if (root.getRight() != null) {
inOrderTraversal(root.getRight());
}
return true;
}
public String callingFunction(MyNodeClass root) {
this.values = new ArrayList<>();
StringBuilder result = new StringBuilder(); // for example
MyNodeClass tempNode = this; // critical to enabling access to this.values
if (this.inOrderTraversal(tempNode)) {
// process the results within this.values
}
return result;
}
}
Not really that difficult nor complex... just took a while to wrap my brain around the problem enough to work a viable solution.
Now that I'm back from my volunteer event, I have some work to do. It's time to revisit K-ary Trees and Binary Search Trees. Coding these up and writing unit tests for these might take a minute, but I'm looking forward to reviewing these data structures and finding key takaway points for future use.
I've battled with these before and I did so again today. For future reference, I need to remember the following to help guide me to a solution, faster:
Often times I struggle with taking instructions a little too literally. This causes me to try again and again to get code to work where it really shouldn't (see [Java Generics, above]{#java-generics}) or is above my skill level to complete in an efficient way. It will help me to remember that when writing code becomes difficult or I keep re-writing code and coming to a dead end, there are better ways to approach and resolve the problem:
My experiences at Code Fellows taught me the importance of breaking down a problem into the smallest possible bits, and working through each individual component carefully. This should help keep me from "coding in circles" and instead, finding a solution that I can then write tests for and start coding, and move forward.
Up until today I have been thinking of Trees as a separate class or structure than Tree Nodes. This has caused some issues:
It is probably better for me if I think of Trees as a Node that might/not have child nodes. Any Tree Node should have the functionality necessary to get/set its value, one or more children, and know how to traverse, and be generic for all types that it could store.
Today I have a volunteer event scheduled that will keep me busy through Sunday. Before that, I coded the Code Challenge and wrote a test for it and it passes! There are probably a few other tests to write to ensure the code is functional in all the expected ways including failure cases, while will be developed over time. For now, I'm calling the code challenge exercise a success, and can safely say that I passed the challenge per the rubric scoring system.
Met with Ryan to go over our project, update the Trello cards, and plan next steps. Made good progress completing several MVP cards, created a few new ones, and updated existing ones. There are a few cards that seemed a little lacking in detail so we added to them when we could, otherwise left a comment reminding us that more definition would be necessary to do work.
Following the meeting I completed the tasks at hand and then got back to work building my Java Code Challenge Libraries, starting with Trees and Queues. They needed to be built from the ground up following the curriculum, which I found to be much easier to do this time around (versus when learning them in classes, earlier). I guess the pressure of everything including homework and new material every day, multiplied by lack of sleep and limited time, fried my brain a bit!
Once I built-out a Binary Tree with Pre-Order, In-Order, and Post-Order traversal methods, I then had to build-out a Queue class so that I could implement a breadth-first traversal method. This required implementing generics as well. All the while I was writing and running unit tests to ensure the code I wrote was working and when it wasn't, I would know quickly and could pin-point the problem and fix it.
I am to the point where I am ready to write the Code Challenge code that I planned-out on the whiteboard, but it is too late to get involved with that right now. When I get a little time I'll get back to it and find out just how well (or not!) I did in the mock interview!
I don't know where the time goes! Actually, plenty of it is spent doing research, learning about aspects of coding, taking care of things around my home and neighborhood, and volunteering in my community. Most recent community volunteer event was Tuesday where the ham radio emcomm team worked on a local repeater system to try and improved its coverage of the service area. No towers were climbed, and progress was made.
Things I've been working on include:
Today and on Monday I spent a few hours doing interview preparation activities, mostly working with behavioral questions, but also looking at some software developer openings around the area. There was a post on a bulletin board I frequent about a remote job opening that could be interesting. The OP works for the company and stated the entry requirements might look very high, but the hiring managers are likely to accept more junior developers for the role. Some of the entry requirements include C#, Azure, SQL, Git, and Selenium -- all of which are things I have experience with. I have some research to do.
Today I completed a technical interview challenge. The expectation was to build a function that accepts to binary trees, counts tree nodes that have no children, compares the two counts, and return true if both counts are the same, false if not. In 40 minutes I was able to build a plausible algorithm, write the code (Java this time!), define my testing approach and tools, and analyze the solution using Big-O notation. The only part I was missing was a step-through of my solution using the identified inputs and outputs, which cost a few points in total. Even without verifying my Java code for syntactical and idiomatically correct, my self-analysis shows I would likely pass a Code Fellows technical interview. I'll write the Java code anyway to get the practice and confirm my assumption though.
Completing that code challenge in Java prompted me to review how Tree data structures are arranged, how to traverse them, and how to and analyze them. Doing this work begged for a new repository so I created one from scratch, and intend to build-out the repo with various code challenges including basic data structures (for reuse) such as Trees, Stacks, Graphs, and so on.
All of this aught to keep me quite busy for the forseeable future!
Friday was busy with lots of tasks in lots of areas, including software. Most of the software-side of things was researching React-js design and techniques including planning, routing, and nav bars. Plenty of time was spent fiddling with CSS and react-bootstrap. The Enigma Bay team is making progress on the site layout based on wireframes and selected color palette, and I have a little work to do fixing up an alignment problem in a Component. Some things I should keep in mind when buiding a responsive site using CSS and Bootstrap:
<img >
tag by setting its class e.g. class="mw-100"
.<div>
tags rather than <p>
and other block or inline tags to improve control over customization. Otherwise, override each tag style, or better yet import a CSS reset file and define your own tag style defaults..parent {
height: 100%;
display: flex;
align-items: center; // horizontal centering
justify-content: center; // vertical centering
padding: 0.25rem; // your choice
}
<div class="parent">{text}</div>
For responsive design, and allowing viewability on varying sized browser windows, try using 'vw', 'em', and 'rem' (relative em) units. Be aware that font styles and browser-zoom levels might cause unexpected results. There is a lot to this, and many resources exist that dive deeper into how to get responsive design working well.
After battling with Bootstrap for a little longer, I was reminded how difficult styling websites can be when mixing it with CSS, because Bootstrap implements margin, padding, and box-sizing automatically, which makes some CSS styling ineffective. I keep going back and forth between "stick with pure CSS!" and "stick with just using Bootstrap" and there is never a winning decision, it is always a draw. At least for the purposes of the current project, the time spent fiddling with style is just practice time anyway, and much of the styling wil be revamped completely as the project moves forward.
This morning I worked on a LeetCode challenge, medium level, in javascript. The goal was to implement a function that takes two non-empty linked lists with data type Integer (Number), and sum the values across lists. Remember elementary school math, summing large numbers like 714 and 237? Like that but with singly-linked nodes, and (of course) the numbers are in reverse-order, which makes carrying-over values a little more difficult. I'm about 75% done and will get back to it in a bit.
Meanwhile, EnigmaBay had a meeting to discuss moving the project forward. We chatted about color schemes, icons, CSS, Bootstrap, and SASS, React Router, and the React Component hierarchy we want to implement. Very productive! We start developing the layout and basic design of the website today.
ESLint with React was reporting some errors and warnings that were unexpected. After reinstalling eslinter and learning there is a plug-in specifically for React, I installed that too. Two elements needed to be udpated in the eslintrc.json file:
Now linting seems to be working as expected.
It has been a busy start to the week. Not all of my activities have been code-related, unfortunately. Several tasks related to volunteer activities came up and I decided to concentrate efforts there to try and meet some deadlines in the coming weeks.
At any rate, I took time this morning to respond to a few interview questions and practiced speaking them aloud in an effort to gain my confidence and organize my thoughts, preparing for when the interviewing starts.
This morning I completed a technical interview challenge: Sum Odd Values in a Binary Tree. Ending (self) score was 34/40 (32 is passing). I was able to depict the problem domain, inputs and expected output, testing approach and basic test cases, write an algorithm and analyze it in Big O notation, as well as write pretty-close-to-working javascript code (minus a few syntactical errors).
To check my work (because testing ones self is dubious) opened a replit to validate my code. Note that I had to create classes to meet the requirements of the challenge:
It was time consuming to write all of this out, but exercising my mind to get to the correct solution is important. I find myself questioning the code I write before, during, and after I write it (before testing it). Perhaps its the test engineer in me.
The next challenge was from CodeWars using javascript. In 40 minutes I completed whiteboarding Kata "Testing 1-2-3" and got very close to a solution. Below are some retrospective commments:
Array.prototype.map( (element, idx)=> { return ... });
and increment idx value within the string concatenation (or template literal).${}
placeholders and back ticks (e.g. code fencing characters).// template literals
let var1 = 1;
let var2 = 2;
let var3 = var1 + var2;
let myString = `${var1} plus ${var2} equals ${var3}`;
Considering my internal anxiety coding with javascript, not all that bad really.
Reactjs oh-my!
I'm glad I started fiddling with React, javascript, and CSS these last few days. Today's adventure was trying to get a React site looking okay and passing props around. Looking back at issues and resolutions:
When importing a collection of data using a json file:
<GameBoard wordlist={words} />
When using React-Bootstrap, be sure to:
npm install react-bootstrap bootstrap
import 'bootstrap/dist/css/bootstrap.min.css';
import { Container, Row, Col } from 'react-bootstrap';
Track Keys and Values when passing a collection as props:
Lastly, whenever it is not clear whether data is being passed around or what it looks like in-flight, use console.log and check it out at run time.
After finishing some tasks around the house, I jumped right in to a 40 minute technical interview challenge. This one was summing odd numbers in a binary tree. It tests the interviewee's understanding on binary trees, including traversal and Node data structures. Whiteboarding these challenges in Miro (and similar apps) is quite difficult because there is an additional interface layer between me and the depiction I'm attempting to draw and layout. When working on a real, in-person, dry-erase board, it is much easier to erase, correct, and draw-out the brainstorming and ideation. Granted, one benefit of Miro (and similar) is duplication of complex drawings is super fast!
It took the full 40 minutes but I earned a passing score because I pretty much nailed every section in the rubrik except for code and Big-O. The failures there were not writing any Big-O evaluation at all, and my javascript code was only 85% complete before the time expired.
To solve this challenge I used Breadth-first Traversal using a Queue, rather than Depth-first using a recursive function because it is more difficult to store Recursive function values/outputs than it is to collect and store data within a while structure.
Code Fellows hosted a Big-O algorithm analysis webinar with guest speaker and alumn Isaiah Burkes. He reviewed why we do code analysis, how it is done using Big-O notiation, and gave a few rules of thumb to help remember algorithm analysis:
The last bulletpoint is referencing algorithms that take multiple input parameters. Each parameter has an impact of the algorithm run time and could significantly add to the run time.
After this I started in on the LingoBingo-js project, working in a dev branch to initialize a React singe-page webapp. The goal is to sort out how to build-out Components so they fit into the existing wireframe design intentions. I plan to do more work through the weekend, and the plan is to pick-up collaborative work early next week.
As happens on most days when I leave my Linux box powered-on overnight, a Printer Added popup appears in the notification area on the desktop. This hasn't been a problem, but my curiosity about it got me researching. It's pretty simple: The CUPS service is restarted at about midnight daily in order to 'roll the log file'. There is a bug filled with Cannonical with discussion, and the basic result is there is not a problem per se, and it can be worked around.
I realized, after reviewing yesterday's technical interview problem js solution, that I failed to nullify a node within the pop()
method. While this is not a problem per se, it is best practice to nullify objects so the memory is freed. For managed code the object will get garbage collected when all references to it are removed. The larger the code base, the more important this design practice becomes in terms of memory efficiency, so is a good habit to get into now.
// updated pop() method code
pop() {
// returns the TOP node or item (LIFO) from the stack
if (this.isEmpty) {
return "Stack is empty";
}
let tempNode = this.top;
this.top = tempNode.next;
this.nodeCount = this.nodeCount - 1;
this.isEmpty = this.nodeCount < 1;
tempNode.next = null; // orphan tempNode from the Stack for cleanliness' sake
return tempNode.data;
}
My Stack's isEmpty()
method is relying on a hidden nodeCount property to compute a boolean return when called. Looking at a best practice pseudo code example, I could instead just check to see if 'head' is null, and so long as I manage the 'head' node reference properly, isEmpty()
should always return correctly and without throwing.
// updated isEmpty() method code
class Stack {
constructor() {
this.top = null;
// this.nodeCount = 0; // this is no longer necessary
// this.isEmpty = true;
}
isEmpty() {
return this.top === null;
}
// this.nodeCount operations removed from any methods that have it
// this.isEmpty interrogations are replaced with this.isEmpty()
// any code where this.isEmpty is calculated should instead point to this.isEmpty()
Earlier this morning I read an update from SalesForce about Heroku free products pricing changes. Yep, that's right, those free Dynos and Postgres instances you've been using for all these year might become charged services. Check out Heroku's Blog Article Heroku's Next Chapter for information from Bob Wise, GM and EVP at SalesForce. Thankfully, no immediate action is needed, but sometime in October I'll need to revisit my Heroku instances and figure out what will be going away and what will stay.
Back to code! I failed another technical interview challenge (couldn't complete in 40 minutes, and was doing it wrong anyway) so I attempted to solve it without a time limit on my physical dry-erase board, and then punished myself by writing out the code in javascript.
I started with a Node class, similar to a linked list Node, but this will be used in a Queue class.
class Node {
constructor(data) {
this.value = data;
this.next = null;
}
}
Then built the Queue class with count, front, and back properties, and functions isEmpty, getCount, peek, enqueue, and dequeue.
class Queue {
constructor() {
this.count = 0;
this.front = null;
this.back = null;
}
isEmpty() {
return this.front === null;
}
getCount() {
return this.count;
}
peek() {
if (this.front === null) {
return null;
} else {
return this.front.value;
}
}
enqueue(data) {
let newNode = new Node(data);
// case 1: no nodes in queue
if (this.front === null && this.front === this.back) {
this.front = newNode;
this.back = this.front;
this.count = 1;
return;
}
// case 2: 1 node in queue
if (this.front !== null && this.front === this.back) {
this.back = newNode;
this.front.next = this.back;
this.count++;
return;
}
// case 3: more than 1 node in queue
this.back.next = newNode;
this.back = newNode;
this.count++;
}
dequeue() {
if (this.isEmpty()) {
return null;
}
let temp = this.front;
this.front = this.front.next;
temp.next = null;
this.count--;
return temp.value;
}
}
Next up is the duck-duck-goose function code. Code Fellows utilized arrow functions for their datastructures and algorithms training assignments, so I followed suit.
The important part of the code starts with the Queue instantiation and loading from the input array. From there the main processing code is pretty short and sweet, but entails two iterating structures, which is not always the most efficient algorithm in BigO.
The worst-case BigO of Time for duckDuckGoose() is probably O(n * k). Thankfully, the Queue datastructure has a O(1) in time and O(1) in space for all of its operations so total time through each iteration is fairly fast and lean.
BigO in space for duckDuckGoose() is more like O(n) because the entire input array is stuffed into the Queue O(1) storage at a time for every item in the array.
const duckDuckGoose = (arr, k) => {
// test for null and empty cases here
if (!Array.isArray(arr) || !Number.isInteger(k)) {
return null;
}
if (arr.length < 1 || k === 0) {
return null;
}
if (arr.length === 1) {
return arr[0];
}
if (k === 1) {
return arr.at(-1);
}
// end null empty test returns
if (k < 0) {
k = Math.abs(k);
}
let myQueue = new Queue();
// enqueue the array!
for (let idx = 0; idx < arr.length; idx++) {
myQueue.enqueue(arr[idx]);
}
// main processing
while (myQueue.getCount() > 1) {
for (let jdx = 1; jdx < k; jdx++) {
myQueue.enqueue(myQueue.dequeue());
}
myQueue.dequeue(); // this should be the kth item
}
// return result
return myQueue.dequeue();
};
It's not always necessary to code all of the edge case tests (depends on your interviewer I guess), but I decided to do it to exercise my software test engineer skills.
Next I wrote some exercises starting with the example case, and added a bunch of edge case inputs and a few larger input cases. Below is the base example case:
let result = duckDuckGoose(['a', 'b', 'c', 'd', 'e'], 3);
console.log('result a-e, 3: ', result);
In the end the challenge isn't really that hard, in fact it was easier to write it using a Queue (including coding the queue in full) than it was to try and solve it will various types of for and while loops.
While updating my notes organization yesterday, I also added some emojis that did not work at first. Some investigating revealed that I didn't have the correct plug-ins selected. Some references that lead me to the correct solution:
GitHub Docs on Publishing GH Pages using Actions
GitHub Docs on Using Jekyll with GH Pages
Jeykyll's GH README defining the jemoji plugin.
Jekyll Docs on Plugins
Sounds like Jekyll-themed GH Pages can be locally tested, which might require some Ruby knowledge - I didn't look too deeply into this as there are more important things for me to research and practice right now.
Technical Interviewing exercise: I attempted to complete a Stack-related technical interview question but could not complete the discussion and solution design within 40 minutes. This is not uncommon for me. So I took an additional 40 mins or so to try and create a Stack using Node just to see if I could do it using replit.com, and I could! Following is the code I wrote:
'use strict';
// node class constructor
class Node {
constructor(value) {
this.data = value;
this.next = null;
}
}
// stack class constructor
class Stack {
constructor() {
this.top = null;
this.nodeCount = 0;
this.isEmpty = true;
}
push(value) {
// node or item is added FILO to this stack and returns nothing
let newNode = new Node(value);
if (!this.isEmpty) {
newNode.next = this.top;
}
this.top = newNode;
this.nodeCount = this.nodeCount + 1;
this.isEmpty = this.nodeCount < 1;
}
pop() {
// returns the TOP node or item (LIFO) from the stack
if (this.isEmpty) {
return 'Stack is empty';
}
let tempNode = this.top;
this.top = tempNode.next;
this.nodeCount = this.nodeCount - 1;
this.isEmpty = this.nodeCount < 1;
return tempNode.data;
}
peek() {
// returns a copy of the value at TOP node without removing it
if (this.isEmpty) {
return 'Stack is empty';
}
return this.top.data;
}
}
While this is not fully vetted (unit tests etc), the properties are updated correctly, and the pop(), peek(), and push() functions operate as expected.
The technical interview question was to track the maximum value within a Stack, so I worked on some code to implement that feature. Below is the additional code:
// the code above...
maxVal() {
let arr = [];
let result = this.peek();
while (!this.isEmpty) {
let temp = this.pop();
result = temp > result ? temp : result;
arr.push(temp);
}
for (let idx=arr.length - 1; idx >= 0; idx--){
this.push(arr[idx]);
}
return result;
}
// end of class definition
The code was all developed using a real dry-erase board and replit. Testing the code required console.log()
and replit breakpoints and their built-in debugger. Here is the rest of the code:
let myStack = new Stack();
let emptyStack = myStack.isEmpty;
console.log('Created stack. emptyStack? ', emptyStack);
myStack.push(100);
emptyStack = myStack.isEmpty;
console.log('Pushed a value. emptyStack? ', emptyStack);
let stackPeek = myStack.peek();
console.log('Peeking the stack, value is: ', stackPeek);
let popResult = myStack.pop();
console.log('popResult: ', popResult);
emptyStack = myStack.isEmpty;
console.log('emptyStack? ', emptyStack);
myStack.push(3);
myStack.push(2);
myStack.push(5);
myStack.push(1);
myStack.push(4);
console.log('stack empty should be false: ', myStack.isEmpty);
console.log('peek should be 4: ', myStack.peek());
console.log('maxVal should be 5: ', myStack.maxVal());
console.log('stack empty should be false: ', myStack.isEmpty);
console.log('peek should be 4: ', myStack.peek());
Just now I noticed that replit has a 'unit tests' tool! Something else to check out for sure.
That will be it for today. There is plenty more to do (of course), and never enough time.
After some meetings with Ryan about our MERN-stack project, I decided it would be a good idea to brush-up on various topics so I am primed for planning and development, especially React and CSS/Bootstrap. While I was browsing around my Code Fellows notes, I realized I did a terrible job of organizing my reading notes and in-class notes, so I reorganized them a bit. Several topics were missing altogether, others were incomplete, incoherent, or just not-quite-done. For some of these items I simply went in to the documentation, referenced authoritative materials, and made necessary edits, updates, and additions. For those topics that are missing, I'll have to create new documentation notes - one example is ReactRouter - which will be added to my cont-ed index of topics.
Despite telling myself I wouldn't do much "techie" stuff today, here I am working through CSSBattles.
Battle #2, Eye Of The Tiger #16 is pretty great. I couldn't finish it in 10 minutes like these guys but that's not really important. The key take-aways are:
display: flex;
always try margin: auto;
in the child box to center it easilyborder-radius: {top-left} {top-right} {bottom-right} {bottom-left}
in that order to control each cornermargin: {top} {right} {bottom} {left}
transform: rotate(ndeg);
will make your margin-adjusting efforts confusing - just remember the previous take-away (tilt your head)A decent overview of flex box.
Details about CSS margin property.
Over the past 2 weeks I have been busy with preparing for, and participating in, volunteer activities. The Multiple Sclorosis NW Division holds fund-raising bike rides throughout the US, and I helped by providing amateur radio and transportation services to promote a successful, incident-free, and enjoyable event for all participants and the MS Society itself. Less than a week later, I travelled into the woods to support Destination Trail's "Bigfoot 200" ultra-trail-marathon through the Gifford-Pinchot National Forest. Again, I provided ham radio communications to support the success of this event in terms of tracking runner's bib numbers as they enter and leave aid stations, as well as ones that "drop out" of the race due to time cutoff or exhaustion. Logistics is another big part of my volunteer efforts in person as well as "on the air" using ham radio, to help arrange supply deliveries, transportation of runners and crew from an Aid Station to another location, etc.
CodeWars challenges are a great way to prepare for technical interviews, especially wnen using a whiteboard to rationally work through the problem and design a possible solution. Practicing javascript challenges will help prepare me for anticipated work in the EnigmaBay team, on the Lingo Bingo WebApp.
Fridays at Code Fellows tend to be busy with streams of final presentations, mid-term presentations, guest speakers, and collective social events for CF students and alumni. Today's JavaScript 401 Finals presentations included a team with Andrew S, whom I hadn't talk to in a while. He was a peer in previous CF classes with me, and it was great to see him present his team's project. All teams presented very well and it was great to see their progress toward graduation!
There was also a Python Midterm presentation. The first team included previous team-mate Liesl, and the team obviously had a lot of fun presenting their app. The next team included previous team-mate Dana H and Gina N, as well as co-Code Fellows team mate Vinny S! Their app searches Wikipedia and finds related articles that link together a "start" and "end" article. The other teams also had amazing projects including a Chess game built from the ground up that included a console version as well as a GUI, and an app that scaped Canvas data and provided graphs, calendaring items, and quick links to common tools and areas of Canvas.
Back into coding practice, I work on CSSBattle.dev again. I need to remember how to make trangles, so here is an example of an upright isocolese triangle in red:
It is important to remember that the vertex angle is determined by border-left and border-right unit settings.
Lots of little work done on the Bigfoot WL Bib Record Form project, and some pretty good collaboration started with a small group of 4-5 others. Success for this iteration of the form looks promising!
Yesterday I spent several hours reviewing bogposts and freebie articles about interviewing. Turns out a lot of my fears about interviewing are not really justified, and my approach to interviewing is what needs to be adjusted. An adversarial interview is not what anyone is looking for (if they are serious about filling a position). Instead, my view needs to focus on researching the company and the position I am interested in, and during the interview use that information to help inform my responses. The research should also answer lots of questions about a company and the position but it cannot possibly answer them all, so I should bring those remaining questions to the interview with me, and learn what I can while I have the inside opportunity to ask them. There is opportunity on both sides, and I need to leverage this to help me have positive interviewing experiences, regardless if an interview turning into an offer.
Over the weekend I began working on a collaboration project with Ryan S in Bellingham. We agreed to work on a mern-stack project, basically rewriting a project I already have underway using DotNet. We are both looking to gain more experience with most (if not all) aspects of software development, but especially javascript, react-js, node, and probably express-js and mongo. We will also benefit from utilizing common software management tools like GitHub and Trello, and following some good practices to plan-out this project. Also, there is already a 'customer' for this project, so I suspect we will some experience with engaging with a client and honing the project to a real use-case. I'm looking forward to working with Ryan, and moving this project forward!
These last few days I learned about:
At some point in the future, I'll want to change-up this format to something like a more formal blog article. I haven't decided yet what it will be, other than not a massively long MD file with a FILO stack of entries.
I finished up the Zip Linked Lists code challenge review by performing a mock whiteboard interview within a 45 minute period and then adding the whiteboard to the solution. This is not really sustainable in that it will cause a tremendous number of repositories to appear in my GH profile with little benefit (to anyone), so I plan to set up separate code challenge repositories for various languages.
Related, I worked my way through a CodeWars challenge in javascript (which I haven't written much of lately). I followed the general rubrik outlined by Code Fellows for a technical interview and produced reasonable code that passed the default CodeWars unit tests. Not that that is everything! So this prompted me to create a new js-specific code challenge repository, so this a future efforts will have a place to live.
Somehow I decided today was a good day to look up how to add emojis to markdown files. There are at least two ways:
:smile:
![smiley](url-to-smiley-emoji)
For example:
:smile:
in supported markdown interpreters results in a
!["smiley"](https://github.githubassets.com/images/icons/emoji/unicode/1f603.png?v8)
results in a vvv large smiley vvv
Here are a couple of references with more info:
Markdownguide.org's Extended Syntax guide
Building Java Projects in GitHub using GH Actions. There is a template in github repo 'actions/starter-workflows' that is a good starter. Originally I copied an existing yml file from a CodeFellows example, but that was designed for a slightly different environment and project, so I had to modify it. There were a couple issues:
git update-index --chmod=
and to add eXecute permissions append +x
to the end.Earlier today was a Code 401 instructor's panel where they discussed current content in those classes. There was a good amount of discussion around C#/DotNet, and TypeScript (which is starting to make inroads to the JS class due to increased use in the industry). There was also good discussion around strategies to deal with learning to code, especially JS, such as breaking down the problem in words, and writing solutions as comments rather than code, and then worry about coding the problem once an algorithm appears to solve the problem at hand.
Today I passed the final technical interview at Code Fellows and am officially an alum! Certificate is due in a week or so!
Passing the technical interview was extremely difficult, and I followed the advice I'd received from Code Fellows instructors and staff: Stick with it, pay attention to the details, break down a problem into the smallest parts, and take care of myself along the way. I will continue to do more technical interview practicing while I job hunt, so that I am well practiced and can more easily get over nervousness during a real interview.
Today I picked-up where I left off with one of my older projects, the Bigfoot Bib Report WL Form. The BigFoot 200 event is coming up and during a recent preparatory meeting the form was re-introduced (much to my surprise and delight) and there was new (and renewed) interest in it. I'm going to try and get this as ready as possible, with help from other interested volunteers to test it and provide feedback on possible improvements.
There are a ton of projects on my pet-project kanban board that I stil need to get to. There is definitely more work than there is time. At least these projects and tasks are centered around the goals of improving my software developer skills in every regard, and prepare me for my next big thing.
Back to root README