Concrete Skills

Concrete skills are something I feel as though I have an abundance, and simultaneously, a lack of. I guess this depends on what kind of skills are being referenced. If data structures, algorithms, or Leetcode is in question, I have some confidence. Not only are these topics I enjoy, but I also have solid knowledge in these areas. When it comes to automating tasks, or something more applicable to my current capstone situation, such as getting a strong grip on Docker and how each part of the project can be integrated with it, I feel… less qualified. 

The problem is, I think I can get to the technical knowledge I have, but only via the technical knowledge I am lacking. These barriers become apparent when working on a large project like the capstone. I look at the backend components, and I feel solid, even with little JavaScript experience. But picking up Vue.js makes me feel like I’m swimming in circles. There’s no point in making a backend without a frontend to support it, and I know this, but I’m not happy to confront it as it means abandoning my comfort zone for some crazy new frontend world.

          The learning pattern on concrete skills puts some much-needed pressure on me. It points out that I can have all the knowledge of theory and all the ability to learn quickly in the world, but if I can’t put real technical skills on a resume, I’ll never make it past the first round of hiring interviews. Rather than trying to find ways around the difficulties I face in everyday software development life, I should highlight my weaknesses and mark them down as learning opportunities.

          There has been a plethora of times in my CS career at which I confront a problem I have been avoiding and the knowledge I gain suddenly seems to apply everywhere. For example, last semester I learned the state design pattern, and because it came with some confusion, I dropped it quickly enough. Now, as I tried to make a Markov chain simulation in Java for my Math Modeling independent study, I realized a state pattern was a perfect fit. It took a couple hours, but I got it down and it feels great not only to have learned and used something new, but to know I have the knowledge to use whenever I need it going forward.

          I think my first focus should be some more surface level skills. As the chapter points out, the question, “If we hire you today, what can you do on Monday morning that will benefit us?” is one of the most important questions of the interview. If my best answer is, “Try really hard to get up to speed,” I’ll be job hunting for a long, long time. My new goal is to collect the skills I don’t know or feel uncomfortable with that are more common and focus my spare time on them. It will make daily life as a developer easier and take me further in my career faster.

Apprenticeship Patterns Introduction

            In reading the introduction to the Apprenticeship Patterns book, I found a great deal of the material to be interesting. Looking at the learning curve of a software developer in the style of the apprenticeship to journeyman to master stages provided a much better framework for progression than I had seen before and putting it in these simple and recognizable terms makes a career feel more tangible. Beyond this, I was quite interested in a couple of the chapter introductions. Chapter 4 focuses on “Accurate Self-Assessment,” specifically the concept of complacency of being a big fish in a small pond. I do a fair amount of reading online about careers in software development, mainly focused on entry-level positions, competitive internships, etc. It stands out to me that many people in the field push and push to start at the highest level that they can, which makes sense in such a competitive environment. Whether this means working at a FAANG company or maximizing total compensation as fast as possible, the focus tends to shift away from becoming the best the one can be and instead on landing in what is generally perceived as the best environment/position. While I can’t say this is at all unreasonable as people have themselves to worry about and not just their software development skills (I know I definitely have this focus too), it can come to the expense of their long-term career. By this I mean we find a place where we want to be in the present and allow this to perpetuate for however long, not to the detriment of our skills as a developer necessarily, but not really broadening our skills either. The book elaborates on this, saying, “You must fight this tendency toward mediocrity by seeking out and learning about other teams, organizations, journeymen, and master craftsmen that work at a level of proficiency that an apprentice cannot even imagine.” This means that getting comfortable is easy, and for most, it’s preferable to be within one’s comfort zone. Getting outside of our comfort zone is so valuable though. I think it’s inevitable to play the game of comparisons with one’s immediate peers, even at our level of being students. It’s saying, “Well, I could go on and learn x, y, and z, but I’m doing better than most of the class at the current topic, so I don’t really need to.” It’s a trap I’ve definitely fallen into. But our class, our little sector of the computer science world is just that: a tiny little sector. It’s more valuable to focus on what we don’t know than what we do know at any level of skill. I love this concept, intimidating as it is, and it provides great motivation.

MongoDB and NoSQL Databases

            In our practice with REST API backends, multiple times we ran into MongoDB usage, as the database we were using for the API was MongoDB. My only previous experience had been SQL/SQLite, so I wanted to know what the difference was. I came to find out there is a world of difference, in fact MongoDB is a NoSQL database (NoSQL meaning… well exactly what you would expect it to mean). I found an article – part of a MongoDB tutorial – from Guru99 called Types of NoSQL Databases, What is & Example which dove into the differences and usefulness of MongoDB and other NoSQL databases. Chiefly, NoSQL DB’s do not require fixed schemas, avoid joins, and are easy to scale, which is perfect for distributed data storage and “scaling out”, which is becoming increasingly essential in the CS world. The lack of schema is convenient too, as it allows for “heterogeneous structures of data in the same domain,” providing for great versatility. The other essential parts of NoSQL include it being non-relational and having a relatively simple API. The four kinds are Key-value pair based, column-oriented graph, graph based, and document oriented. Key-value pair based means data is stored in pairs (with a key and a value), which is optimal for large datasets and heavy loads. Column-based means that work is done on separated columns with values in single columns being stored contiguously, performing well with aggregation queries. Document-oriented DB’s (MongoDB is one) also function as a key/value pair, but in this, a value is stored as a document, which is stored in JSON or XML. It is not optimal for high performance or aggregate structures, like Key Value or Column Based. Graph based stores entities and relationships between them. Each entity is a node and each relationships is an edge, defining the relationship. This is different from relational DB’s inn that Graph DB’s are “multi-relational.” NoSQL DB’s commonly query with a key and a GET request. The CAP theorem is also important to NoSQL because it guarantees at most two out of the following three: consistency, availability, and partition tolerance. This is a key limitation of NoSQL DB’s. The last key to NoSQL falls on the concept of eventual consistency, meaning that changes to data on one machine must be reflected on other replicas eventually. Where the standard for RDBMS is ACID, NoSQL is BASE: Basically Available, Soft state, Eventual consistency. The article goes on the list advantages, disadvantages, and summarize itself before coming to a close. I thought this was very interesting to learn, as I can see how different DB styles can reflect the needs of a project or client story. I wasn’t sure why we were using MongoDB; I kind of took it as a given. But this reading broadened knowledge, so now, if I am able to build a REST API of my own over the upcoming break, perhaps I can find the optimal DB for my needs, or help me better understand future projects once I join the workforce.

Learning JavaScript

As my interest in learning Javascript grows, I have started to try and strategize how I should go about learning it. I have heard of several JavaScript frameworks, so I was wondering if I should start with one like Angular, Vue, Ember, or something, and in my research I found a blog post by Francois-Xavier P. Darveau with a very telling title: Yes, You Should Learn Vanilla JavaScript Before Fancy JS Frameworks. This is a post which details why Darveau believes that learning vanilla JavaScript is so important. He starts with a short story of his time in college in which he started to learn Node.js for a project and rather than quickly find libraries and do some Stack Overflow style copy/pasting to get the project working, he dove in and tried to do everything himself. Although it was time-consuming and arduous and was not exactly optimal, he had learned far more behind the scenes than he would have otherwise. He emphasizes that learning all the shortcuts from frameworks and libraries without knowing the how’s or why’s is more akin to pretending than real knowledge. He then explains the meaning of vanilla JavaScript, if not inferred before, as “plain JS without any additional libraries.” He notes that, of course, frameworks and libraries can be extremely useful and time-saving, a lack of vanilla JS knowledge can leave one helpless if something goes wrong or the field collectively decides to hop over to the next new best framework. Some framework pros and cons are detailed as well. Pros: abstracting hard code, shipping code faster and increasing development velocity, and focusing on an app’s value instead of its implementation. Cons: When work scales up and apps become more complex or multiple teams are working on multiple apps, there will no doubt be times when a deep JS understanding is needed to get everything to go smoothly. If a vanilla JS foundation is strong, the only thing changing when getting into a new framework will be mainly syntax. The speed at which new useful frameworks come out is faster than one can master them on their own, but with a vanilla JS understanding, you can already be a step ahead. He then provides plenty of resources for how to learn JS and where it can be studied. I found this very useful as I hope to learn much more JS soon. I have just done some work with Node.JS in order to implement a new REST API endpoint and I hope to get down JS as it becomes increasingly prominent in the CS world. I am also doing an independent study related to mathematical modeling and linear algebra using MATLAB in the upcoming semester, so maybe there will be an opportunity there to apply my JS knowledge.

The Power of Functional Programming

As I have started to learn some about Javascript, I am very intrigued by the new territory and the strangeness that comes with it, at least for someone like myself, with most of my experience coming from object oriented programming languages like Java and C. As I now know, Javascript is a functional programming language, which has some fundamentally different structures and uses. For this reason, I have started to looked into the usefulness of functional programming, as languages like Javascript and Python are quickly on the rise. I found an article on Xiaoyun Yang’s personal blog entitled Why Functional Programming From A Developer Productivity Perspective which has helped me make some more sense of the intent and uses of functional programming. The article starts with basic info on FP, stating how object oriented programming came to popularity in the 80s with the use of GUIs and how, “it’s easier to program things that use a fixed number of operations for an unlimited number of operation,” but how now, “stateful programming is more of a liability” since, “there is an increasing emphasis on asynchronous, distributed, multi-core and cloud computing.” The article then dives into FP design patterns, which explain its usefulness. The intent is for functions to act as, “pipes for data to travel through,” with Higher Order Functions taking functions as input, and polymorphic function adding to reusability and versatility. The first pattern is the Loop Pattern. The emphasis is on abstraction. In the example, for loops are used for arrays of different types, and the goal is to get rid of the type by, “[parameterizing] the loop action as a function parameter and the initial value as a data parameter.” This provides for the reusability of the function in different contexts. The next pattern is Types. The article compares Scala being type-safe to Javascript. This means, “you can impose the argument type and return type when you first define your function in Scala.” This means for non-type-safe languages like Javascript, the onus is on the programmer to ensure clashing types do not lead to errors. While sometimes type inference in Javascript can be convenient, it can create problems when working with different types. The third pattern is Monads. This means that one can use monads instead of, “hard coding error handlers,” with a monad essentially being a wrapper. There are so many errors to worry about when handling user input, so this is advantageous. The last pattern is Monoid. An example is given for a function to find is any strings in array(s) are not empty. It shows that whatever order the arrays are given to the function, or wherever the unempty string exists, the function still works, preserving associativity and commutativity. Monoid laws help verify correctness. The article finishes by stating that FP promotes reusability and modularity through abstracting functions. This is all new to me and I hope this knowledge helps me soon, as the next language I intend to learn will be a FP language like Javascript or Python. It is essential to keep up with the fast-paced world of computer science.

RESTful API Basics

            As we start our learning for our final project in our class, we have started to learn about and work with RESTful API architecture style (REST API), so I have started some research and done further learning myself. I found a great article from by Margaret Rouse with an wide view of the application program interface, called RESTful API. She breaks down what it is, how it works, its uses, its constraints, challenges, and some background information. REST uses the HTTP requests of GET, PUT, POST, and DELETE for data use and access. This API is based on representational state transfer, which is what the acronym stands for. It works by, “[Breaking] down a transaction to create a series of small modules. Each module addresses an underlying part of the transaction.” Commands are used to obtain resources, and resource’s states is called a resource representation. As previously mentioned, the commands are: GET to retrieve a resource, PUT to modify/updated a resource, POST to create a resource, and DELETE to remove a resource. The idea is for users to access networked components with stateless calls, no information being retained by the REST services. This statelessness makes REST “useful in cloud applications.” They are scalable and can be “redeployed if something fails.” It is very useful for efficient internet usage and is very compatible for distributed environments, and is used by the likes of Amazon, Google, LinkedIn, and Twitter. With cloud and microservices growing in popularity and usage, REST is sure to grow alongside. REST adheres strictly to 6 key concepts. There must be a uniform interface under a single URL. It must be client-server based, dividing request-gathering concerns on the client and data access, workload management, and security on the server. There must be stateless operations, as mentioned previously. Any state information must be managed on the client. Caching is essential for resources unless “explicitly indicated that caching is not possible. It must be a layered system, like a hierarchy to the architecture. There must be code on demand, meaning that “a server will send back static representations of resources,” or “when necessary, servers can send executable code to the client.” Sticking to these requirements can be difficult, which presents the challenges of endpoint consistency, response time and data size, defining paths and locations, security, authentication, request scope, testing, and error handling. Since REST is useful for the aforementioned reasons, this is worthwhile and understandable though. I expect to use this information in my final project, which should be dealing in a REST API, so this will be very useful to me in the near future. It is very interesting and exciting, and is growing to the top of the computer science world.


Factory Design Pattern

In keeping with my recent learning with java design patterns, I have been learning about the Factory Design Pattern. It is defined as a creational pattern by the Gang of Four and is very widely used because of the plethora of applications that it has. This seemed to be one of the best design patterns to learn as I saw a great many recommendations to do so in my research on design patterns. In the Factory Method Pattern article from Java T Point, the design pattern is made by, “[defining] an interface or abstract class for creating an object but [letting] the subclasses decide which class to instantiate.” In other words, if the client requires multiple similar behaviors, the Factory Design Pattern is used to choose the required subclass instance to complete the required behavior. The article outlines the key advantages to this design pattern, including the promotion of “loose-coupling” because of the lack of application specific classes into the code. It then gives a couple of examples for usage including a class not knowing what subclasses will be required. There is then a simple UML diagram which shows a small example of how an electricity bill may be calculated using the Factory Design Pattern. This example is then expanded upon. First, an abstract Plan class is created. It contains an abstract getRate method and a concrete calculateBill method. The subclasses show the real usefulness of the design pattern. There are 3 subclasses: DomesticPlan (with a rate of 3.50), CommercialPlan (with a rate of 7.50), and InstitutionalPlan (with a rate of 5.50). Each class implements the getRate method, which sets the Plan class’s rate variable to their respective rates. From here, a GetPlanFactory class is created which uses the Plan class and its subclasses to return a Plan object. The one method here is getPlan, which takes a string variable and has a set of if statements, each of which returns a different Plan subclass object depending on the string. Finally, the GenerateBill class is the one which the client interacts with. It asks the client the name of the plan needed, which the PlanFactory class uses to return an object of the one of the Plan subclasses. Then, units of electricity are taken from the client. The Plan subclass object then calls getRate to get the rate associated with the plan, and then calculateBill to tell the client the total charge for electricity usage. Although the explanation seems complicated, it is quite simple and clean in implementation, and extremely useful when one does not know which of a given set of behaviors will be required. I expect I can use this design pattern quite frequently in my personal, school-related, and professional coding. 

State Design Pattern

            In keeping with my recent learning about Java Design Patterns, as outlined by the Gang of Four, I have recently been doing research on the State Design Pattern. I came across an extremely useful article which details the Design Pattern logic, implementation, upsides and downsides, as well as giving an overall evaluation. The article is titled “State Design Pattern in Java,” by Denis Szczukocki, and starts by explaining that the main usage for the State pattern is “to allow the object for changing its behavior without changing its class.” It is also cleaner than a project cluttered with if/else statements for controlling object behavior. The basis is that an object who’s behavior is dependent on a specific state can easily change states and therefore change behaviors without the creation of a new object and the classes responsible for this behavior will be “tightly coupled.” Within the pattern, there will be 2 essential classes and a number of extra classes dependent on the number of states required. The first is the context class. The context class delegates object behavior to the other class, the state class, but the context class is the one used by the client. The state class is usually an interface, with the concrete state classes implementing this interface and dictating behavior. The article gives the example of a package with 3 states: ordered, delivered, and received. There is a package class, which is the context class, and contains methods to move to the next/previous states and print the status as well. When an instance of the package class is created, really what happens is that an instance of the first state (ordered is created). When ready, the package object can move to the delivered state, and then the received state, all of which have different behaviors. The three behaviors in the PackageState interface common to all concrete states are next, previous, and printStatus, each which has a different behavior depending on the concrete class of the package. The article then notes that a possible downside to the State design pattern is that, “the state becomes hardcoded, which is a bad practice in general.” This taught me how to use the State Design Pattern and why it is good practice. I plan to use this in future projects when I can in order to practice, as well as to implement good project design practice. It is understandable and not terribly difficult to implement, so I know this can help me in my future work.