Apprenticeship Patterns – Breakable Toys

In this pattern, the authors discuss the importance of building what they call “breakable toys.” The context they present is one in which the apprentice needs an outlet for failure, so to speak, because in order to gain the experience needed to excel in the software development field they must make mistakes and learn from them. This can be difficult in a professional setting as management and other superiors may not be expecting failure from the new apprentice. Hence, making mistakes in the work environment can have negative repercussions. While it’s impossible to avoid failure in the computer science field, it can be somewhat contained by adopting this pattern and breaking things in a low-stakes environment where the only one effected by failure is the apprentice himself.

The authors stress the fact that the only way to progress in the software development field is to make lots of mistakes and even just flat out fail sometimes in order to learn and grow as an individual and as a software craftsman. The authors advise apprentices to make breakable toys which resemble what they might be building at work. This allows the apprentice more flexibility in design and a lot less stress when compared to the professional setting. One example of a “breakable toy” the authors suggest for apprentices is putting together a wiki. They go on to show that by taking on this type of project the apprentice can learn new things about a variety of topics ranging from “HTTP, REST, parsing, web design, caching, full-text search, databases, and concurrency.”

I have to say I certainly agree with the authors after reading about this pattern. Even before I read this I have been experimenting with “breakable toys” of my own. When it comes to learning new things within the field, I am a very hands-on learner so building things and breaking them are a must if I hope to gain new useful skills. Since I work in Security, some of the side projects I have going on at the moment are things like building my own firewall and deploying a Security Onion instance within my home lab in order to gain first hand experience regarding best practices for Network Security Monitoring.



Apprenticeship Patterns – Expand Your Bandwidth

This is the first pattern in chapter 5 of Apprenticeship Patterns which focusses on how to address the steep learning curve associated with picking up new programming languages and/or practices. The context the authors present in this pattern is one in which the apprentice has acquired a set of “basic skills” that must be improved in order to become a journeyman. They describe the problem as being that the basic skills held by the apprentice are insufficient for high-level projects that require a more extensive knowledge base and/or skillset. The authors use the analogy that up to this point the apprentice has been sipping information through a straw but the time has come where they must drink from the fire hose of information.

As a solution, the authors suggest apprentices should “expand [their] ability to take in new information.” To do this, the authors advocate for apprentices to not just read books pertaining to knowledge they seek to gain but rather utilize a number of resources in combination with the reading to increase retention and understanding. Some of things they suggest are signing up for Google Reader and subscribing to software development blogs, following “luminaries” on twitter, subscribing to online mailing lists and answering people’s questions, as well as physically or virtually attending technical conferences. The authors note that when the so-called fire hose of information is turned on it can be difficult for an apprentice to get other work done as most of their time will be taken up by the process of ingesting a plethora of new information. Hence, they recommend that this pattern should not be used for more than a few months otherwise it may have yield diminished returns by decreasing an apprentice’s development velocity.

I found this particular pattern to offer some highly valuable advise in terms of how to really push my development career forward. I think that I can actually put this pattern to practice after graduation as I am moving into a position that requires a strong understanding of python programming. Up until this point in my career, I would describe my python programming skills as being basic but in order to excel in my position I will need to acquire a deeper set of skills. After reading this, I decided that when I start my new job I will try to put my mouth to the fire hose information, so to speak, in order to gain essential knowledge and put myself in a position to excel.

Sprint Retrospective – The Final Sprint

This last sprint cycle for my team was probably the most productive sprint in terms of producing code but we ran into a lot of issues when it came to dealing with Promise objects. As I have mentioned in my previous blog posts, when making calls to to a pouchDB instance (i.e. db.put(), db.remove(), db.get(), etc…) those calls return what is known as a Promise object. At I found a good definition of Promise objects. They describe them as “a proxy for a value not necessarily known when the promise is created.”  Hence, using promises allows developers to write asynchronous code fairly easily. The reason I say this is because asynchronous functions may have multiple expected outcomes/return values without knowing the order in which they will be generated. Before promises, asynchronous functions were handled using callbacks which would either deal with any errors the function might generate or execute the function as expected. You can refer to this link for a more in-depth explanation on the benefits of using Promise Objects instead of callbacks for asynchronous code.

Below is a diagram depicting how promises operate:


As you can see above, promise objects may be chained together using .then() which provides the capability to easily write functions with multiple asynchronous actions expected.

Initially, my team and I didn’t have a great grasp on the concept of Promise Objects and were expecting our code to return explicit values. Here’s an example of our addDoc() function in which we expected to get a boolean value to be returned:

Screenshot 2018-05-02 21.22.17

The problem with this is that our function was actually returning  a promise object which that returned true when the necessary conditions were satisfied. After doing some research and working with the team who were writing the offline data capture service we realized our function was actually returning a Promise Object. Furthermore, we figured out that we could expand the functionality of our addDoc() method by utilizing the chaining of promises. With this knowledge, we re-wrote our addDoc() method so that it expected a Promise Object to be returned and could update an existing record if it’s ID was found in the PouchDB instance. Here is what the addDoc() function looked like after making those changes:

Screenshot 2018-05-02 21.25.19

Testing functions that return promise objects also proved to be quite difficult. Here is a screen shot, taken from my gitHub page, depicting the test we wrote for the addDoc() method:

Screenshot 2018-05-02 21.43.24

As you can see, highlighted in red, we initially had our function call inside the expect() part of our test. Then, we changed our test (shown highlighted in green) by moving the expect() inside of the .then() call after the addDoc() function. Subsequently, our test successfully passed and we thought we were on the right track. However, some of our functions had long chains of promises with multiple asynchronous actions expected. Thus, some of our tests were producing output that was hard to explain because we were still expecting our code to execute in a synchronous manner like if-else statements. In other words, anticipating that the result of each .then() call would be returned in a synchronous fashion, which was not the case.

In hindsight, a better method of testing our functions may have been just simply testing whether the correct pouchDB function was getting called the right time. We were trying to test whether the promises returned in our functions were, themselves, returning correct values. It may have been better practice to just log the responses of promise objects called in our code rather than testing the expected return values since asynchronous code may return things in an unforeseen order.



Apprenticeship Patterns – Find Mentors

In this apprenticeship pattern, the authors present a context in which developing software professionals are “spending a lot of time exploring blind alleys.” They then describe the problem by saying that the software apprentice is “walking along a path” but having trouble being prepared for “what’s around the corner.” In other words, they are describing the difficult task all software apprentices face when trying to learn new skills and master their craft. The authors then go on to remind the reader that every software developer who is considered to be a “master” in the field, has walked the same path and knows exactly what that path entails.

For the solution to this problem, the authors suggest that software apprentices “seek out” those that are considered to be masters who are further along on “the long road” and attempt to learn from them. However, this suggestion comes with some warnings. They point out that as an apprentice it may be more difficult to spot the true master craftsman in the field. To counteract this concern, the authors advise that apprentices ” be supervised by a series of mentors who possess varying degrees of mastery.” Additionally, they remind the reader that “no one knows everything” so it is ill-advised for an apprentice to be under the assumption their mentor is infallible in terms of their software development skills and expertise. By upholding this mindset, the apprentice may be able to recognize their mentor’s weaknesses without feeling like they have outgrown their mentor.

The authors also address the issues and concerns that coincide with reaching out to more experienced professionals within the software development field. They recognize that this task may seem extremely intimidating to most apprentices due to fears of rejection or being seen as “strange” by a potential mentor but they assure the reader that these risks are low when compared to the payoff of being mentored by someone who is much further down “the long road.” The authors also provide testimonial from a developer named Dave in which they illustrate these payoffs. Dave reminisces on the time he “uncharacteristically” approached a more experienced software developer named Wyatt at a conference and later went on to exchange emails with him asking to be mentored. Wyatt agreed to become Dave’s mentor and the two went on to meet periodically throughout a year. Dave describes his interactions with Wyatt as “pivotal in (his) progress” in becoming a skilled practitioner of agile development.

After reading this I plan on taking the authors’ advise by “lurking” on message boards and community web pages with the intention of finding potential mentors and valuable information regarding my particular field of study within computer science.


Apprenticeship Patterns – Stay in the Trenches

I have to say I did not fully agree with this particular apprenticeship pattern. The authors reiterate their views from the other patters here by explaining that software apprentices should shy away from promotions that involve managing others rather than maintaining positions that heavily involve writing code. The specific context of the problem in this pattern is that you are being offered a promotion that will “pull you away from programming.” The promotion in question is one in which you may receive higher pay but will involve much less technical skills and require less programming.

I understand that the authors are trying to encourage readers to stick with programming in order to enhance their skills and write better code but I think that at some point in one’s career it is important to consider roles that involve management. Part of the reason I say this is because if good programmers never become managers than developers in the field will end up with lousy managers that aren’t understanding when it comes to handling difficulties a team of developers might face. Also, just because you take on a role that involves managing people doesn’t mean you’ll never write code again. For instance, many developers have side projects, such as open source projects, that are unrelated to their work which allows them to continue to hone their craft of software development.

I agree with the authors that developing software professionals should always continue to work on enhancing their skillset but I don’t agree on their anti-promotion/ anti-managerial outlook. Skilled developers occupying the role of manager may prove to be good mentors for those working under them. Furthermore, many projects can benefit from having someone with a strong background in programming making the important decisions. These decisions can range from architecting the project, choosing different tools and/or programming languages to use, and assessing whether applicants are a good fit for the team. If the only people managing teams of developers are those with little experience in programming then the teams could really suffer by not having the right personal with the right expertise and not having all the necessary tools/information they need to be successful.


Sprint 5 Retrospective – Testing Our PouchDB Service

Unfortunately my team and I were unable to meet the goals we set for ourselves at the beginning of this sprint cycle. The biggest issue we’ve been facing is writing tests for our offline storage service which implements pouchDB. In researching how to write meaningful  unit tests in Angular for services that implement pouchDB, we have found few helpful resources. The pouchDB API, which can be found here, provides little documentation on this subject so we have been forced to refer to git-issue pages and various tutorials. The issue with these resources is they tend to be somewhat outdated and don’t exactly match our particular use case.

My team and I have referred to the pouchDB API when it came to writing methods for our offline storage service. Our methods are pretty straight forward as they implement standard pouchDB functions such as get(), put(), and remove()  for getting, adding, altering, and deleting data from the offline storage database. So, for the most part, we believe our methods are correct and function as intended. However, in order to be sure our methods are functioning correctly, we need to write meaningful unit tests in Angular. The first test we wrote just checks to make sure the pouchDB in-browser database is successfully created. This test passed and when we looked at the web page Karma opens when the tests run we can open up the developer tools and see that our database is in fact created. This is depicted in the screen shot below:

Screenshot 2018-04-18 10.51.16

Although we can see that our pouchDB in-browser database is instantiated, we run into a mess of problems when trying to call pouchDB functions. For instance, when trying to add elements into the database we use pouchDB’s “put()” function and pass in a string which then gets parsed as a JSON object. To test this method we created a mock patient object, in JSON format, at the beginning of our test class and tried confirming it was being successfully added by checking the Karma test page in the browser. I should mention that the process of debugging has been quite difficult when trying to figure out why tests aren’t passing because many of the error messages  generated after tests fail seem to lack essential descriptive information. I say this because we are rarely given specific line numbers from our service indicating where the errors occurred. Instead, we seem to get a bunch of references to files that we aren’t concerned about. I feel that this may be partially due to our lack of experience in writing unit tests in Angular.

I was actually able to make some progress today in testing the “addDoc()” method for our offline storage service. Previously, we had gotten the test to pass but I was left unconvinced that it was actually working as intended because I could not see any data being stored in the in-browser pouchDB database. After some trial and error I was able to get the method to work and physically see the data in our pouchDB database. Here is a screen shot depicting the data that was successfully added:

Screenshot from 2018-04-18 21-02-57

Now that I understand how to get mock data into our offline storage database, I will relay this information to my team and we should be able to make some real progress as this has been one of the main issues holding us up.

Apprenticeship Patterns: Be the Worst

At first glance, I thought this particular apprenticeship pattern seemed a bit absurd. The reason I say this is because I couldn’t imagine why anyone would actually want to “be the worst” in terms of skill level and knowledge on a team of seasoned software developers. However, after reading the rest of what the authors had to say in this pattern it started to make a lot of sense. This pattern reiterates some of the ideas presented in other patterns such as “The Deep End” and “Stay in the Trenches.” Essentially, the authors explain that it is more beneficial to be a “small fish in a big ocean” rather than a “large fish in a small pond.” What this means is that by taking on more difficult projects and/or working with more experienced developers you will provide yourself with more learning opportunities and walk away with a number of invaluable skills that you will pick up from your more experienced colleagues as well as your own personal experiences.

The authors note that this idea might seem crazy as it clashes with cultural norms that seem to advocate the idea that one should try to obtain the highest-paying position with the most superiority as soon as possible. They talk about how adhering to this cultural norm can curtail ones own self-development process by getting stuck in a position that lacks any real challenge. Another thing in this pattern that I found encouraging was the testimonials from various software developers describing their own experiences of “being the worst.” While you’d think that being the least skillful and/or knowledgeable team member would be an undesirable experience, all of the testimonials in this pattern seem to illustrate positive experiences of self-improvement and success.

At the end of this pattern the authors suggest that software apprentices should try to reach out and observe teams that operate at a high skill level in attempt to “be the worst” but in way that guarantees personal-growth. I think this apprenticeship pattern has provided me a new sense of confidence going forward. I’ve learned that it is completely fine to “be the worst” in a team of experienced software professionals because when you are, you have the largest number of learning opportunities that help push you further down the “long road” of becoming a true software craftsman.

Sprint 4 Retrospective – Narrowing our Scope

At the beginning of this sprint cycle my team and I thought we had a pretty good handle on what we needed to accomplish and how we were going to do it. In the previous sprint cycle we had figured out how to instantiate a pouchDB in browser database as well as add elements and get them back through the console. To test whether we could get pouchDB working within the ng2-amrs application we added some code the app.component.ts file. Once we were sure that pouchDB could work in the application we moved forward in writing the pouchDB offline storage service. However, we were trying to incorporate open-mrs api calls in our offline storage service which proved to be much more complicated than we originally though. To remedy this problem we decided to break it into smaller pieces and Conor drew up a diagram in balsamic to help us not over think what we needed to accomplish. Here is the diagram Conor made:

 Offline Data Module Architecture

In this diagram my team’s responsibility is the “Offline Data Storage Service.” Instead of trying to do everything at once, we decided we just needed to write a service that will store JSON objects in an in-browser database. By narrowing the scope of what we needed to get done to one task we have been able to make more meaningful progress.

During our team meetings we were able to get started in writing an add method for our offline storage service as well as corresponding unit tests. Through writing this method and it’s corresponding unit tests we found that pouchDB databases use JSON objects by default making our job a little easier. We have not pushed any new code onto our group’s GitHub page but that will be one of the first steps we take in starting the next sprint cycle.

In our last team meeting we were able to get everyone caught up on where we were at in the project and assign specific tasks to each group member going forward. After narrowing our scope down we decided that the main methods we needed to focus on for our offline storage service included add, put, delete, and clear. The add method will store elements in JSON format in the pouchDB database. As for the put method, it should take in the id of an element already stored in the database and alter the information of that element. Finally, the delete method will take in the id of an element in the database and remove the element, this method will also return the JSON object that was deleted. We also discussed implementing a clear method that could erase all data stored in the pouchDB database but we have not decided whether or not this function will be necessary to accomplish our goals.

Moving forward, my team and I will have to contact the Ampath developers and ask if they agree with the direction we are heading in. We will also need to communicate with other teams to make sure that our service can coexist/ be implemented in the other teams’ code. If everything goes as planned, we should have a functional offline storage service by the end of the next sprint cycle and we should also be able to start piecing together our piece of the project with other teams’.

Apprenticeship Patterns: The Long Road

In this section of Apprenticeship Patterns the authors discuss what a developing software professional can expect from his or her career choice in the long run. The talk about how becoming a software craftsman does not happen over night and if someone hopes to master the the craft of software development they should be aware that they are in for a life long journey of learning and self-improvement. The authors describe the context for this pattern by discussing how the values of modern society sometimes conflict with the the practices necessary to become a master in the software development craft. They talk about the values of people in modern society consisting of “overnight celebrities, rising stars, material wealth, and quick results.” However, in the field of software development “quick results” can often lead to poorly written and/or bug ridden code. Also, the authors make a point in describing the problem that exists here being that modern values might compel a developing software professional to take the highest paying job they can find and quickly race towards their first promotion in an attempt to stop programming and start managing other people and making more money.

While higher paying salaries are definitely a key factor in propelling individuals to take up software development, the authors suggest this shouldn’t be the main contributor when it comes to making career decisions. Their solution to this problem entails thinking ahead and keeping in mind what will bring you the most joy and the highest sense of achievement. At the end of this pattern, in the action section,  the authors provide a thought experiment in which they ask you to think about where you will likely be in 10 years and what you will be doing. They then ask you to do the same thing for 20, 30 and 40 years from now and write down all of your answers. By doing this you may be able to gain some insight on what types of jobs/positions will be best suited for your own personal goals. I thought this was a great exercise and I found this pattern to be quite insightful. I also definitely agree with the authors on the idea that modern values don’t usually align with successful software development practices. After reading this pattern I believe that I will have more confidence in making career choices in the future through partaking in the thought experiment and referring to my answers when I’m faced with difficult choices within my professional career.

Sprint 3 Retrospective – Implementing Offline Storage

Similar to the last sprint cycle, this sprint consisted mostly of research rather than actually writing code. Right at the beginning of this sprint cycle my team and I faced some issues regarding getting pouchDB installed in the ng2-amrs application. Not every team member ran into the same issue though. In fact, Ben was able to install PouchDB into the application first try without any complications. As for myself and my other team members, upon installing pouchdb using the command “npm install pouchdb @types/pouchdb” some of the other dependencies were erased causing the application to throw a bunch of errors when we were trying to start it. To fix this problem I reinstalled all the dependencies in the order listed in the Read-Me file. After that I was able to run the application without errors and ensure that pouchDB was still installed as a dependency.
After we got pouchDB successfully installed the next step was to figure out how to instantiate a pouchDB instance to store data locally. After a lot of trial and error I found that importing pouchdb into the app.component.ts file and writing code to make a new pouchdb database in the constructor allowed me to see the new database when I started the app. To see that the database was created, I had to open up the browser’s developer tools and go to application resources. After that I tried adding elements to the pouch database and getting them back. The nice thing about pouchDB is that the commands associated with pouchdb are pretty straightforward and it uses json objects by default. To add new elements to a pouchdb database named “db” you simply write “db.add(…)” with the element you want to add inside the parentheses. Then to retrieve that data element you can simply write “db.get(…)” with the element’s id inside the parentheses.
This sprint cycle also gave way to a whole new issue that my team will have to deal with in the upcoming sprint. In my last retrospective blog post I talked about pouchDB’s asynchronous capabilities with any server running couchBD. We learned this sprint cycle that the open-mrs server is not compatible with couchDB so we will be unable to apply pouchdb’s asynchronous functionality to this application. This may be a pretty big set back as we now have to develop our own service to ensure that data stays up to date between the open-mrs server and our in-browser pouchdb database.
Moving forward we will need to reach out to AMPATH and figure out how they want us to implement the offline storage component. Some of the things we will need to consult with them about are how the code should be structured, whether or not we need more than one pouchdb instance, and how we should synchronize the storage between the in-browser pouchdb database and the open-mrs server. As far as code structure goes, we need to figure out if where we instantiate the pouchdb instance is a safe place or not. I was thinking that we may want to write an offline storage module that handles all the imports and pouchdb logic and then import that module into the app.component.ts file. Next, we need to figure out if user credential information should be stored in a separate pouchdb database than the patient data to possibly provide better security. We will also be consulting with some of the other teams to try an figure this out. Finally, since we cant make use of pouchdb’s asynchronous functionality, we need to talk to the people at AMPATH to get some advice on how we should synchronize offline storage with their open-mrs server.
Another thing I did this sprint cycle is I started to put together an offline storage service that will be used to store patient records in our pouchDB database. The code I wrote for this can be found here: I based some of this coded off of the advice given from one of the AMPATH developers on slack. Unfortunately I have not been able to test this code which should pull patient data from the open-mrs server and store that data in a pouchdbd database in the browser. Testing is going to be another issue that my team and I will have to address this sprint cycle as none of us are too familiar with how to write tests in angular not to mention tests that will ensure the in-browser database is storing what it’s supposed to. I’m looking forward to this next sprint as I feel like we are actually making some progress and hopefully we have a lot more to show for the end of next sprint now that we know how to get a pouchdb instance up and running.

Create a free website or blog at

Up ↑