Author Archives: Namson Nguyen

Sustainable Motivations

Programming is automatically motivating for programmers when they have the freedom to work in their preferred manner. However, apprentices often face real-world challenges with projects that have changing demands. Such projects can be rigorous, chaotic, and frustrating, making it essential for programmers to have a constant motivation to adapt and remain resilient. While there are some days where everything flows smoothly, there are also more common days that are filled with complex and tedious tasks, particularly in money-driven programming jobs.

Motivations for programmers can vary, including financial goals, the sheer enjoyment of programming, or building a reputation through open source projects. However, relying solely on financial or reputational motivations can lead to what’s known as the “Golden Lock” phenomenon. This trap involves sticking with known skills because they’re lucrative, even if they no longer align with personal growth or interests. To combat this, an ambition for constant improvement towards mastery is vital, helping developers realize when they’re falling into these traps and guiding them to seek new challenges.

While passion for programming is valuable, it can also lead to overcommitment. For example, Marten Gustafson found himself overcommitting to projects due to his passion, resulting in project “death marches.” It’s essential to nurture this passion while maintaining a balance with other life aspects to avoid burnout.

David Wood offers a simple yet enlightening piece of advice: “Do what you love and the money will follow.” Following this advice helps developers discover that doing what they love fuels their creativity and energy, leading to greater financial rewards in the long run.

To better understand personal motivations, it is encouraged that programmers list at least fifteen motivations and then another five. This exercise helps identify motivations based on personal feelings versus external factors caused by other’s judgment and perception. By prioritizing the top five motivations and keeping them visible during challenging times, programmers can stay focused and resilient on their journey.

On a personal level, I find programming very entertaining and fascinating. But as a student, I often find that my motivation for programming can become fueled by academic reputation. One motivation could be, for example, a fear of getting a bad grade and not making the Dean’s list. While this is certainly a real feeling and truly motivates me to meet the expectations of my professors, it stops at that. Such a motivation is not to become a great programmer, but rather, to become successful in school and therefore in my career. While this way of thinking will probably get me through university, it does not guarantee me a successful career.

Programming offers intrinsic motivation, but navigating the challenges of real-world projects requires adaptive motivations. It’s crucial to balance financial goals with personal interests and ambitions for mastery. By avoiding the Golden Lock, embracing learning opportunities, and nurturing passion while maintaining balance, programmers can find long-term success and fulfillment in their careers.

From Chapter Three, “Walking the Long Road” in Apprenticeship Patterns by Dave Hoover and Adewale Oshineye

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Sprint 2 Retrospective Blog

With new experience gained form Spring 1, I entered into Sprint 2 starting strong with more understanding of the basic workflow and how to navigate Thea’s Pantry on GitLab.

As a team, we all worked very well together in all stages of the sprint. There was good communication through Discord and SMS to coordinate meeting times both in person and online which shows by our ability to complete twenty-three out of the twenty-four weight we planned for the start of the semester. Because we were more used to the workflow process, we were able to spend more time together figuring out our more in-depth issues to implement button functionality to the AddInventoryFrontend project.

Some issues we ran into however, was not being able to build and run the Frontend to see how our vue file code ran. Instead, we had to rely on a vue playground which we found online to test and run our code. In addition, we were unable to access the wireframe to edit it, so the team resorted to detailing the revised wireframe through PowerPoint Presentation. These were simple issues that can be fixed in the next Sprint. As expected, we did not repeat any of the workflow mistake we had done last Sprint.

For the next sprint, we plan to have a “Workflow tips” shared document that includes all our mistakes from Sprint 1 and their solutions so that we do not make the same mistake again. For example, instead of waiting to review everything at the end, the team will review issues as they are completed. We also know to create merge requests directly from the issue, and to edit the merge request properly so that it meets all workflow requirements.

For the next sprint, we plan to continue working on the AddInventoryFrontend project. The first step before implementing the revised button wireframe would be to fix the frontend so that it can run on GitPod rather than having to rely on Docker. Then we will add code to allow the frontend to run on devmode, which makes it so that updates pass through as we work on the code rather than requiring the frontend to be rebuilt each time a change is made. After both of these are completed, then we plan to confirm that the current vue code works. Once that is confirmed and running, we will then update the frontend to reflect the revised wireframe.

This Sprint, I was not the SCRUM master, but I attended all our meetings and worked with my team to come up with solutions to our issues. I would say I am much more organized than last Sprint and am happy with the progress I and my team were able to make together.

Activity links:

GitPod Dev Environments: https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/inventorysystem/documentation/-/issues/9
Description: Verified that all Thea’s Pantry projects have the correct extensions, linters, and pipeline stages.

AddInventoryFrontend Redesign: https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/inventorysystem/addinventoryfrontend/-/issues/39
Description: Created a revised wireframe for AddInventoryFrontend. The revised wireframe will be added to Thea’s Pantry GitLab in Sprint 3.

Implement Frontend Wireframe: https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/inventorysystem/addinventoryfrontend/-/issues/45
Description: Developed the submit and cancel buttons following the basic wireframe before revision.

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Integration Testing

Integration testing is a critical aspect of the software development cycle, ensuring that individual software components work together cohesively to form a functioning system. It focuses on testing the interactions between modules to confirm that they function as intended when combined into a single system. This makes it easier to identify and address errors that may arise during the integration of multiple components.

Various types of integration testing methods exist, each offering its own advantages depending on the project’s complexity and requirements. These methods include Big Bang, Top-Down, Bottom-Up, Incremental, Sandwich, and Hybrid approaches.

Big Bang Integration Testing involves combining all modules and testing the software system in its entirety. While this method is straightforward, debugging can be complex if issues arise during testing. Although it is simple, this approach allows for quality assurance teams to evaluate the entire system at once, saving both time and effort.

Top-Down Integration Testing prioritizes higher-level modules for evaluation, followed by detailed assessments of lower-level components. This method is effective for thoroughly examining the entire system and breaking it down into smaller parts to identify any inconsistencies.

Bottom-Up Integration Testing begins with critical lower-level modules and gradually works up to higher-level ones. This approach is the reverse of top-down testing and is suited for projects where bottom components are more important top ones.

Incremental Integration Testing involves integrating modules one by one and verifying that each module performs as expected. This testing strategy is effective for detecting problems early in development and ensures that issues are addressed before advancing to further stages.

Sandwich Integration Testing combines top-down and bottom-up integration methods to provide a comprehensive overview of functionality. This approach is suitable for projects requiring both an initial top-down overview and verification that each lower module serves its purpose.

Hybrid Integration Testing combines various integration testing techniques. This method allows developers to choose multiple tests to ensure the system’s flawless operation, depending on the project’s goals and requirements.

Implementation of integration testing involves several steps:

1. Define the scope, identifying test scenarios

2. Prepare test data

3. Create test cases

4. Set up the test environment

5. Execute test cases

6. Monitor and analyze test results

7. Report and track issues

8. Retest and verify

9. Sign off and release the application.

There are many strategies to integration testing. I am curious to try the Big Bang strategy to test my code on a holistic level. While it is simple, it is also thorough, which I think is a perfect strategy to begin with when practicing integration testing.

As a short recap, integration testing ensures that all modules perform according to set criteria. Through integration testing, software developers can confidently roll out solutions and ensure seamless performance when deployed.

References:

The Complete Guide to Integration Testing by Marquel Ellis

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Test-Driven Development

Usually, the traditional method to developing code is to start with a design, implement that design, and then test the implementation to ensure that it runs as smoothly as intended. However, test-driven development (TDD) completely changes the software development process by emphasizing writing tests before code, turning tests into an iterative, ongoing practice.

Unlike the traditional waterfall model where testing is an end-of-cycle event, TDD integrates testing at every step. The TDD cycle consists of writing a failing test, implementing the feature to pass the test, and then refactoring the code. It’s deeply rooted in Agile principles, promoting iterative development, customer feedback, and adaptability.

Good adaptability comes from TDD’s ability to ensure that each development round begins with a clear, testable goal, which fosters collaboration and ensures that there is quality assurance in every phase. This is done by writing unit tests for core functionalities before implementing the feature. Once the feature is implemented, the code is refined to pass the test. Eventually, through iterative cycles, the entire application is built.

TDD offers numerous benefits for software delivery teams, including improved collaboration, robustness, and cost-effectiveness. Applications developed using TDD tend to be more robust due to the quick feedback loop, allowing bugs to be detected and resolved early on in the development cycle.

Moreover, by starting simple, organizing tests, regular refactoring, and building a comprehensive test suite, TDD leads to improved design and architecture, lowered long-term costs, increased confidence in code changes, and effective documentation.

Practicing the TDD method in class was an eye-opening experience. I was able to learn so much about testing and developing software at the same time. Because I am often guilty of neglecting to write my test cases, this type of development is good for getting me more comfortable and into the habit of writing stronger test cases.

Overall, TDD brings reliability, efficiency, and reduced maintenance costs to software development. Its structured testing approach, coupled with comprehensive test cases to optimize the development process, improving the code quality. TDD’s compatibility with CI/CD practices makes it essential for delivering reliable and high-quality software efficiently. I will definitely practice writing code using the TDD method more.

Source: Test-driven development explained by Jacob Schmitt

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Art over Craft

Richard Stallman calls programming a craft rather than a fine art, focused on building useful objects rather than purely aesthetic creations. While programming can be truly elegant and beautiful, its real purpose is to solve a customer’s problem. This is what makes it a craft.

The pattern “Craft over Art”, in this sense, is all about strong relationships and delivering value to customers. It is important to prioritize customers’ needs over personal artistic expression, because true craftsmanship involves building something that is both beautiful and useful. Software should never be simply beautiful but useless artifacts.

However, there are often many demands in software development, many of which are conflicting. It is important that a developer balance these conflicting demands, for example, delivering value to customers while adhering to professional standards. This is what it means to sacrifice the beauty of code for utility.

By focusing on the craft over the art, a developer gains many benefits. A developer is able to look past doing things solely for self-satisfaction, and instead, is able to aid customers and help solve real problems for real people while honing their craft.

To apply this pattern, software developers should find an opportunity to prioritize utility over beauty throughout the day, building a habit of being aware of the tradeoffs. A developer could also reflect on past choices where they prioritized artistry over utility and suggests afterwards think about alternative choices to understand the potential outcomes. “Craft over Art” advocates for a balanced and customer-focused approach to software craftsmanship.

I particularly found this pattern very helpful, because I find myself often working to make something perfect to the point where it hinders me from getting my work done. And often, because I have spent so much time making the code “perfect”, I grow so attached to how my it looks and is running, that I struggle with the idea of refactoring it to make it function better.

Understanding the difference between craft and art will make it easier for me to see my code as something that is always changing and improving rather than something that I try to write perfectly the first try. There is always room for change, to hone my craft.

From Chapter Three, “Walking the Long Road” from Apprenticeship Patterns by Dave Hoover and Adewale Oshineye

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

A Summary on Unit Testing

Unit testing is a crucial aspect of software development that focuses on testing individual components of a software product. Nickolay Bakharev writes a great article detailing the uses, advantages, and strategies to unit testing in his article, Unit Testing: Definition, Examples, and Critical Best Practices.

Unit testing involves writing tests for functions, procedures, methods, objects, or other entities in an application’s source code. The goal is to ensure that each unit of the software performs as intended and meets requirements.

Some advantages of unit testing are that it is able to detect problems early, thereby reducing costs. It is also heavily test-driven, easier to refactor the code, and allows developers to keep documentation of the system’s behavior.

Unit tests usually consist of four phases:

1. Planning and setting up the environment

2. Writing test cases and scripts

3. Executing the tests

4. Analyzing the results

A common approach to unit testing is something called Test-driven development (TDD), where tests are written before the actual code, resulting in a high-quality, consistent codebase.

Unit testing can also be used for security purposes by creating tests that focus on the security controls of the smallest testable unit of software. Security unit tests can help catch security flaws early in the development lifecycle which saves the costs of potential security breaches.

Various unit testing techniques include structural unit testing, which examines the internal structure of the code, functional unit testing, which tests the functionality of an application component, and error-based techniques such as fault seeding and mutation testing.

There are many examples of unit testing in specific frameworks. Some include Android unit testing, Angular unit testing, Node.js unit testing using Mocha, and React Native unit testing using Jest.

In order to use unit testing most effectively, the developer must write readable tests, write deterministic tests that always pass or fail on the same code, automate unit tests in a continuous integration process, and avoid multiple asserts in a single unit test to maintain clarity and reliability.

I found unit testing to be a very useful technique to learn in class. While I knew the basics of testing, this was the first time I actually implemented it into code. I will try to add these unit testing techniques to my research project code.

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Sprint 1 Retrospective Blog

Being the first sprint of the Capstone class, there was a lot for me to learn working as a team and also as an individual.

As a team, we all worked very well together in all stages of the sprint. There was good communication which helped us coordinate meeting times both online and in-person. Evidence of our synergy would be through the fact that we were able to meet our estimated 20 weight completion by the end of the sprint. I would attribute the large success of our sprint to our commitment to meeting at least once in person every week throughout the duration of Sprint 1. This allowed us to really work together as team to figure out the issues and workflow, which was brand new to us all.

However, it was not all sunshine and daisies. The team made multiple mistake along the way which had slowed us down on occasion. Two big problems for all of us was navigating GitLab and getting used to the workflow. Aside from getting lost and figuring out the UI, we were unsure at first how to post our issues and how to create branches for our changes. It was also confusing how and when to approve merge requests. We had waited for all our issues to be completed before doing the review, which created merging conflicts and caused certain pipelines that were dependent on the other issues to fail.

For the next sprint, we plan to have a “Workflow tips” shared document that includes all our mistakes from Sprint 1 and their solutions so that we do not make the same mistake again. For example, instead of waiting to review everything at the end, the team will review issues as they are completed. We also know to create merge requests directly from the issue, and to edit the merge request properly so that it meets all workflow requirements.

As for me, an individual member of the team, I acted as SCRUM master and worked to communicate with the professor for the team during meetings, preparing notes and organizing the thoughts of the team. However, I had failed in some parts to organize tasks for myself, missing one stand-up post due to negligence. Now that I have a better understanding of how the workflow and meeting dates work, I will be more prepared in the next sprint.

Activity links:

GitPod Dev Environments: https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/guestinfosystem/guestinfointegration/-/issues/23
Description: Moved Settings and Extensions from VSCode to GitPod Dev Environments.

Add AlexJS Linter: https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/inventorysystem/documentation/-/issues/6
Description: Added AlexJS Linter to pipeline check.

Move `commands` to `bin`: https://gitlab.com/LibreFoodPantry/client-solutions/theas-pantry/inventorysystem/documentation/-/issues/5
Description: Changed command folders to bin to avoid naming convention conflicts.

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Apprenticeship Patterns: Expose Your Ignorance

One of the patterns addressed in Chapter 2 of Apprenticeship Patterns by Dave Hoover and Adewale Oshineye is titled “Expose your Ignorance”. It is a pattern that helps a programmer identify their weaknesses so that they can better know how to promote their personal growth.

When a company hires a software developer, they are trusting that the software developer is well suited for the job and knows what they need to know to do the job well. However, sometimes even the most experienced developer may come across an issue or technology with which they are unfamiliar.

To combat this, it is necessary to “expose your ignorance”. This does not necessarily mean to down-sell oneself by listing out all weaknesses and struggles, but rather, to be open with one’s learning progress and improvements. Being open is a road that leads to trust and reputation in any software developing team.

How does one healthily expose ignorance?

Ask questions! Learning from experienced software developers is the most direct way to becoming an experienced software developer oneself. Asking questions exposes ignorance, but it also exposes one’s ability and willingness to learn.

What happens if one does not expose ignorance?

The opposite to exposing ignorance is hiding it, and while it may save face in the short term, hiding ignorance will only stunt personal growth. This is bad for both the software developer and the team who depends on the software developer to be able to do their job well.

What are my personal experience with exposing ignorance?

When I was starting off with my research projects, I suffered from “imposter syndrome”. There was simply so much I didn’t know and had to learn to catch up and progress through my research. However, instead of hiding in my shell and trying to keep up a facade, I swallowed my pride and let my advisor know when I wasn’t understand something, or when I needed help. I had to remind myself that this fellowship is a chance for me to grow and gain experience! My advisor does not expect me to know anything and is there to help me learn.

Because I was willing to ask questions and exposed my ignorance, I was quickly able to learn and gain a deeper understand of my research project.

From this experience, I became to like being surrounded by people who know more than I do because it gives me the opportunity to learn so much. It exposes my ignorance not only to those around me, but arguably more importantly, to myself.

Seeing where I struggle pointed out clearly to me, it gives me the chance to address that weakness by doing the necessary research and practice to strengthen my understanding in an area that I would be otherwise unaware.

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

What is White, Black, and Grey Box Testing?

Software testing is broken into three main types: white, black and grey box testing. All three types have the same goal, however, they achieve these goals differently.

The blog “Black box vs white box vs grey box” from Shake does an excellent job in breaking down and explaining the unique roles of each testing type.

Black box testing:

The black box testing type focuses on the interface of the software. Software testers working with this type of testing approach the application from the user’s perspective. Because of this, no code of the program is required.

Usually, testers use the basic input/output technique to test the program, making sure that it is working as expected. The main goal of black box testing is to find usability issues and design flaws that affect the user experience.

White box testing:

While black box testing focuses on the user’s perspective, white box testing is all about testing how the program executes its function and therefore needs access to all the program’s code.

The main responsibilities of white box testing include identifying security vulnerabilities, evaluating broken paths, and testing outputs, loop errors, and data flow of the program.

This is achieve through the use of three main techniques:

  1. Statement coverage — it ensures that every statement in the code is run and tested at least once. This process also identifies all the “dead code” or unused statements and branches.
  2. Branch coverage — it is similar to statement coverage, but rather than individual statements, branch coverage ensures that all possible branches of the code are executed by detecting all the conditional and unconditional branches, then executing them.
  3. Path coverage — this technique uses multiple test cases to cover every possible execution path through the software.

The purpose of these technique and white block testing as a whole is to reduce the risks of bugs developing later on development.

Grey box testing:

As the name suggests, grey box testing includes a combination of both white and black box testing. Testers approach the program from the user’s perspective, but with access to some of the internal structure of the program.

The goals of grey box testing include, examining the risk level of all variables in the software, identifying re-occurring errors, and optimizing the number and quality of tests by balancing coverage and effort.

Coming into CS443, the terms “white”, “black” and “grey” box testing were all foreign to me. While I had recalled hearing the terms being said, I never fully understood nor retained the concepts.

This article was very insightful in teaching me the concepts of white, black, and grey box testing. I think realistically, most software testing would be done in the grey box. This is because the advantage of grey box testing is taking the advantages of white box and black box testing. For a final thought, I hope to have the chance to do some white box testing to see what that would look like in a developer setting.

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.

Introduction to Apprenticeship Patterns

The book Apprenticeship Patters: Guidance for the Aspiring Software Craftsman by Dave Hoover and Adele Oshineye is a powerful tool for both beginner and seasoned software developers.

Hoover and Oshineye introduce software development as a craft constantly needing to be honed. The term “craft” has been widely defined and generically used throughout multiple sources. However, Hoover and Oshineye define what they mean by “software craftsmanship” using a list of values. While the list is long and descriptive, the main gist is that the craft of software development is all about improvement. There is always room for improvement, achieved through an open mind, the sharing of information and resources, and the courage to experiment and discover through process.

To help developers hone and perfect their craft, Apprenticeship Patterns contains numerous different strategies or “patterns”, helping the reader not only to grow, but to grow most effectively.

One thing that resonated the most with me was the book’s theme on the importance of having an attitude of growth. Without such an attitude, it is easy to become stuck in one’s own bubble of perceived competence and thereby losing focus on learning. I could have all the resources available to me, every book, tutorial, guide, and mentor; but if I am not open and willing to move away from my perceived area of “expertise”, my growth will surely be stunted.

In addition to the right mindset, I found chapter four very insightful, which goes into detail about how a developer also needs a healthy environment where growth is promoted. An environment that fosters learning and communication is the key difference between a struggling software developer and a thriving one. Because of this, a developer should be careful not to be too content being the biggest fish in the pond. There is always another pond with even bigger fish and more nutrients. Hoover and Oshineye emphasize repeatedly how important it is to let go of perceived competence to focus on learning. Sometimes, the best environment is one that is a little uncomfortable.

Software development is a huge field filled with so much potential. There are dozens of languages that take years to fully experience, learn, and understand. All of this — and so much more — is taught through experience and through trial and error.

In addition however, one other important tip from Hoover and Oshineye is to learn from the best of the best. They stress the benefits of reading books which are filled with the knowledge of experts in the field of software development. Reading is the most direct way to gain knowledge made possible through an open mindset and a resourceful, learning environment.

While growth and learning are important, I also think it is important to rest and enjoy the journey. The word “craft” also implies “artistry”. Therefore, I believe a software developer should not focus too much on “becoming an expert” but also to explore and appreciate the beauty of the art of software development.

From the blog Stories by Namson Nguyen on Medium by Namson Nguyen and used with permission of the author. All other rights reserved by the author.