Category Archives: Week-14

Apprenticeship Patterns – Craft over Art

The problem of this pattern is a very common situation; virtually any time you are building something for a client. You are tasked with producing something that will solve the client’s problem. While you could follow a basic, common method, you also could explore new solutions and build something more custom. The pattern then determines that the solution to this problem is to rely on the tried and tested method. The justification is that your job is to create something functional and you must prioritize that over all else.

I’m not sure how I feel about the proposed solution to this. I would say I overall disagree. Firstly, just because you’re trying something new doesn’t mean its entirely original. There are varying degrees to which you could try something new. So I disagree with the absolutism of the statement. Next, I don’t think that taking the time to create something new is entirely selfish. Just because you could hack together something functional quickly and deliver it to the client doesn’t mean that they won’t have a successful, or even better product from you creating something original. In fact, I think in a sense it shows how much you care for the client. Rather than giving them something cookie cutter, you chose to think specifically about their problem rather than force it to match some other problem. When it comes to coding, that practice might significantly aid performance, for example. Cookie cutter solutions to intensely computational problems can’t be as efficient as specified unique solutions.

Lastly, not all developers have the time to create original content in their free time. If developers spend all of their time copy pasting the same projects, how will the industry as a whole ever advance? So once again, it isn’t just about advancing your own individual skills. I feel there is a disconnect with this pattern. The author seems to be referring specifically to artifying the job, but their descriptions are much more vague than that and can encompass less “negative” practices. When it comes to treating every job like a unique art piece, I’d generally be against that since I don’t think it is a good business model. However, it depends mostly on what the client wants. Perhaps the client wants that level of connection with the craftsman.

From the blog CS@Worcester – The Introspective Thinker by David MacDonald and used with permission of the author. All other rights reserved by the author.

Confront Your Ignorance: Filling in the Gaps

Photo by Ann H on Pexels.com

Software development often involves a large variety of interconnected tools, patterns, standards and ideas which must be understood at a functional level to be able successfully apply them to the project at hand. Sometimes the sheer number of things which require your understanding can feel overwhelming, and going into a project without knowing absolutely everything you might need to know often leads to stress regarding the gaps in knowledge versus what is required.

The pattern discussed in chapter 2 of Apprenticeship Patterns, (link: https://learning.oreilly.com/library/view/Apprenticeship+Patterns/9780596806842/ch02s06.html) discusses the idea of confronting your ignorance, by which the authors mean that you should seek out and eliminate any holes or gaps in your knowledge, rather than allowing the “ignorance” to be a detriment to yourself. More specifically, the pattern describes the process of picking one skill, language or technology to focus on at a time, and working to better your understanding of that one idea. Rather than trying to focus on everything at once, you focus on learning one skill at a time, generating a more “precise” understanding of it than if it were being lumped together with other subjects.

This idea makes a lot of sense, intuitively you might think it would be second nature to begin learning a new topic by focusing only on that topic instead of trying to do everything all at the same time, but often that is exactly what ends up happening. Whenever there is a larger “stack” of tools to learn, I sometimes find myself actively trying to absorb everything all at once, because I feel that maybe slowing down and taking each single tool or topic on by itself might slow things down too much. This hesitance not to “multitask” when learning new ideas makes it harder to really focus on any one thing when trying to become familiar with a large number of tools and ideas in a short timeframe.

Overall the major ideas of Confront Your Ignorance are simple, and easy to implement , the big drawback being the time it will likely take to focus exclusively on one topic can often take time away from other activities. Like most patterns discussed in Apprenticeship Patterns, finding an effective balance between this pattern and others is important and likely dependent on context most of the time.

Book Referenced:

Apprenticeship Patterns: Guidance for the Aspiring Software Craftsman

https://learning.oreilly.com/library/view/Apprenticeship+Patterns/9780596806842/ch02s06.html

From the blog CS@Worcester – CodeRoad by toomeymatt1515 and used with permission of the author. All other rights reserved by the author.

Apprenticeship Patterns: Dig Deeper

Another issue I have been facing as of late is related to my understanding of the systems and software that I use. I often find that I am able to learn just enough to meet the requirements for my assignment, but lack perspective of exactly what is going on behind the scenes. One class in particular that this was true for would be data structures, which was quite challenging considering I had no experience with any facet of it before then. This resulted in me learning exactly what I needed, nothing more or less, to succeed. Upon reflection of this class, I decided to choose the Dig Deeper pattern to discuss this week.


The first major tip given is one that I have often encountered in other patterns, being to break a problem down to its most abse form. As stated in the pattern, most programming issues can be broken down to an incorrect algorithm. Once the problem is broken down, you can examine each part of the problem in great detail, giving you a more in-depth understanding of both the problem and the tools used to solve it. Furthermore, the pattern states that you should focus on reading as much original documentation as possible since many articles may lose some information in translation. As for retaining knowledge, once again breakable tools are referenced, which I have discussed further in a previous post. Any new understanding can be represented in the form of a fun hobby program or blog post. Throughout the process of reading these patterns I have realized how interconnected they are, often relying on each other to result in well rounded software design principles.

One thing to note is that it does feel a bit strange to try and relate to these patterns, particularly because they are very clearly written for someone currently in the workforce in a software development position in mind. Regardless they still have some knowledge that will likely benefit developers at a variety of levels. This perspective being less relevant to me is my only real complaint, other than this I have found these patterns quite helpful! This will be my last post for the time being, but after everything I have ready I may have to return to this blog later on. Thank you for reading and, as always, if you want to read this yourself it will be linked below!

Source

https://www.oreilly.com/library/view/apprenticeship-patterns/9780596806842/ch06s04.html

From the blog CS@Worcester – My Bizarre Coding Adventures by Michael Mendes and used with permission of the author. All other rights reserved by the author.

What is AngularJS?

In the Software Constr. class, I was presented for the first time with the angularjs front-end web framework. AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and lets you extend HTML’s syntax to express your application’s components clearly and succinctly. AngularJS’s data binding and dependency injection eliminate much of the code you would otherwise have to write. And it all happens within the browser, making it an ideal partner with any server technology.

I had the chance to work a little with this framework and I understand some part of it how it works. Angular has the following key features which makes it one of the powerful frameworks in the market.

 MVC – The framework is built on the famous concept of MVC (Model-View-Controller). This pattern is based on splitting the business logic layer, the data layer, and presentation layer into separate sections. The division into different sections is done so that each one could be managed more easily.

Data Model Binding – You do not need to write special code to bind data to the HTML controls. This can be done by Angular by just adding a few snippets of code.

Writing less code – When carrying out DOM manipulation a lot of JavaScript was required to be written to design any application. But with Angular, you will be amazed with the lesser amount of code you need to write for DOM manipulation.

Unit Testing ready – The designers at Google not only developed Angular but also developed a testing framework called “Karma” which helps in designing unit tests for AngularJS applications.

There are some advantages for this framework.

Since it is an open-source framework, you can expect the number of errors or issues to be minimal.

Two-way binding – Angular.js keeps the data and presentation layer in sync. You do not need to write additional JavaScript code to keep the data in your HTML code and your data later in sync. Angular.js will automatically do this for you.

Angular can take care of routing which means moving from one view to another. This is the key fundamental of single page applications; wherein you can move to different functionalities in your web application based on user interaction but still stay on the same page.

It extends HTML by providing its own elements called directives.  So why Angular? While AngularJS does not suit every project idea, it builds amazing apps. The most valuable reasons of AngularJS usefulness lie in their concepts and benefits that they provide. Nowadays with all marketing strategies and technologies to find a worth product has become a real challenge. Besides, it is easy to lose yourselves among all those benefits that are listed by every product. And it is even harder to find those ones you really need and that really suits your idea.

From the blog CS@Worcester – Tech, Guaranteed by mshkurti and used with permission of the author. All other rights reserved by the author.

What is the difference between a software framework and a software architecture?

Software frameworks are reusable “semi-finished” software for domains (such as ERP, computing, etc.) that implement common parts of the domain and provide well-defined points of variability to ensure flexibility and extensibility. In other words, the software framework is the softwarenation of the results of domain analysis and the template for the final application in the domain.

With the expansion of software scale, wide application and the development of software reuse technology, the software reuse based on subroutine and class has a lot of shortcomings:

(1) The library of the subroutine is becoming more and more huge, which makes it difficult for its users to master

(2) Most classes are too small to do all the useful work by themselves

It is for these reasons that a set of classes (modules) are considered as a whole in reuse, resulting in a software framework. The software framework contains at least the following components:

(1) A series of modules to complete the calculation become components

(2) The relationship between components and the interaction mechanism

(3) A series of variable points (hot spots, or adjustment points)

(4) Behavior adjustment mechanism of variable point

Developers through the software framework behavior adjustment mechanism, peculiar to the general application domain software module bound to the variable point of a software framework, and got the final application system, this process is called software example of a software framework, the existence of software framework allows developers will be the main energy on the development system of the module, so as to improve software productivity and quality.

The behavior adjustment mechanism of the software framework refers to how to adjust the variable part of the framework for the specific application and how to add the method and rules of the specific application module at the variable point.

Ii. Software architecture

Software architecture is a sketch of a system. The objects described by software architecture are abstract components that directly constitute the system. The wires between the components describe the communication between the components explicitly and in relative detail.

Software architecture, by definition, is divided into two camps of ‘constituent’ and ‘decision-maker’, which are described as follows:

The componentized view of software architecture is that the system is described as computing components and their interactions. It has two very obvious characteristics:

Focus on the object of architectural practice — software, with the software itself as the object of description.

This paper analyzes the composition of the software, and shows that the software is not a whole in the sense of “atom”, but a whole composed of different parts connected through a specific interface, which is very important for software development.

Decision-makers believe that software architecture involves a series of decisions, mainly including:

Organization of software systems

Choose the structural elements that make up the system, the interfaces between them, and the behavior that these elements exhibit when they cooperate with each other

How do you combine these elements so that they gradually synthesize into larger subsystems?

The architectural style used to guide the organization of the system: these elements and their interfaces, collaborations, and combinations

Software architecture is concerned not only with the structure and behavior of the software itself, but also with other features: usage, functionality, performance, elasticity, reuse, understandability, economy, and technical constraints and trade-offs.

Personal understanding: When software engineering has a certain scale, software development does not exist in the form of data structure + algorithm, but “divide and conquer” software based on many factors such as technical choices and user needs. The main task of the architect is to divide the software into different modules and define the interfaces between modules.

Sources:

https://softwareengineering.stackexchange.com/questions/229415/difference-between-an-architecture-and-a-framework#:~:text=An%20architecture%20is%20the%20the,that’s%20designed%20to%20be%20extended.&text=Frameworks%20are%20specifically%20designed%20to%20be%20built%20on%20or%20extended.

From the blog haorusong by and used with permission of the author. All other rights reserved by the author.

DRY (Don’t Repeat Yourself)

https://thevaluable.dev/dry-principle-cost-benefit-example/

I’ve chosen to talk about a very simple design principle this week called “Don’t Repeat Yourself”, DRY for short. It’s a topic that is covered in this class according to the syllabus and I chose it since its similar to another topic I covered YAGNI in that they’re easy to understand design principles. The meaning is quite self-explanatory, don’t repeat code since if you need to change the behavior of a certain project, you’d have to rewrite numerous lines of code if DRY wasn’t applied. However, applying this principle to everything isn’t efficient either. Trying to apply DRY everywhere causes unnecessary coupling and complexity which also leads to more difficulty changing behavior. According to the link above, using DRY means emphasizes knowledge above all else. What it means by that is that when designing and constructing software, one should have the knowledge of when to apply DRY and when not to for the sake of the readability and efficiency of the code.

In that context, DRY reminds me of the importance of resources in a computer when running something. If you want something run faster, you’ll have to sacrifice more memory. And when you want something to have more memory, you’ll have to sacrifice more speed. Both are valid choices; it really depends on the needs of the software and the user. Say for example, I want to create a program that lists all numbers from one to 100 which I do by writing out a thousand lines of code in which each prints a number. However, if I implement DRY, then I could create an integer variable r and a loop which prints the value of that variable and increments it by one until r equals 100. But the case where I want to alter the behavior to list every odd number between one and 100 is where thing get a bit interesting. In the DRYless scenario, I can simply delete the lines of code that print even numbers. Yet in the scenario with DRY, I’d have to add a condition that skips printing variable r for that iteration of the loop. You have to sacrifice complexity for readability and vice versa. Though the choice is ultimately up to what works best in the current situation. Like in my example, the added complexity from DRY doesn’t really harm the readability, in fact it improves it in some ways, at least in my opinion.

From the blog CS@Worcester – Rainiery's Blog by rainiery and used with permission of the author. All other rights reserved by the author.

Design Patterns

Earlier this semester, we worked on an assignment regarding design patterns. I found this interesting as I took a deep dive into learning more about facades. As I’ve gotten deeper into the computer science program, assignments and projects have naturally gotten bigger and bigger. I was excited to learn more about facades, because it relies on two aspects important to large scale projects: simplicity, and restriction. It can make complex projects a bit easier to follow, as well as limiting what a client has access to.

While I learned a lot about facades through this assignment, I felt that I didn’t personally study enough about the other gang of four design patterns. To familiarize myself further that what I learned in class, I listened to episode 34 of the “complete developer podcast”, focused on design patterns. It wasn’t a thorough as I would have liked, but I was able to familiarize myself a bit more on behavioral and creational design patterns. Having studied facades closer, I was already a bit familiar with structural patterns. From their explanation, these 3 types of design patterns have a lot of cross over but tend to be categorized separately primarily for human understanding. I would have liked if they discussed some actual pattens within the creational, structural, and behavioral categories, such as certain ones they use more often than others.

One key takeaway I had with this podcast is how universal these object-oriented design patterns are. One of the hosts was appreciatively saying how he’s a .net developer but could talk to a Java or Ruby developer about any of these design patterns. They may not be familiar with the language, but they would be able to follow the structure of the code. The patterns themselves aren’t that complicated, but they’re capable of facilitating much more complicated programs. I also thought it was interesting, they referenced how some languages don’t need these patterns depending on the level of abstraction built into it.

I found their criticisms of design patterns to be the most useful to me. The hosts discussed certain misusages of design patterns, and these are things I can keep in mind going into the future. In particular, as some programs evolve, they may require a different design pattern than what’s originally implemented. What I take away from this is that it’s important to diagram your project before you get too invested in it. A simple UML diagram can likely show you if you’re using the right pattern, or if you’d need to change as you get further into the project.

From the blog CS@Worcester – Derek's Design by dereksspace and used with permission of the author. All other rights reserved by the author.

Refactoring

No one likes messy code, and everyone likes simplified code, so I was interested in learning more about refactoring. While the idea of enhancing code sounds fairly intuitive, I wanted to learn more about tips and practices to use when refactoring code. In the past, I’ve been guilty of leaving my code in rough shape, until after I finished. While my habits have improved, I still have a lot to learn in these regards. To help learn some refactoring methods and practices, I listened to episode of 78 of Full Stack Radio, with guest Ben Orenstein. Orenstein, dubbed “one of the refactoring guys”, formerly worked at Thoughtbot in Boston, and now offers a course on refactoring, as well as gives lectures on the subject.

What I really liked about this podcast with Orenstein is how direct he was with all his tips. None of his advice sounded complicated, because he used very simple, explicit language. In fact, this type of language demonstrated one of his tips: “make the implicit explicit”. For example, give full words when naming object. If there’s an intermediate equation in the middle of a method, leave comments or naming conventions that clearly state why it’s there and what it leads to. Too often, I’ve used vague abbreviations in my naming conventions. While in most small-scale programs, this isn’t an issue, I realize this could be very problematic on larger projects.

“first make the change easy, then make the easy change.”

One of the best tips I thought Orenstein offered during the podcast was preparatory refactoring, or to refactor code before making changes, rather than refactoring while making changes. In this regard, your preemptive changes can cause you to have to make less changes further down the line. He gave an example of once refactoring code prior to a new feature being implemented. In the end, the new feature was pulled and not implemented, but his refactoring in advance still improved the codes functionality.

I feel like I took a lot away from this, from small tips to things I never thought about. Something that caught me slightly off-guard was when Orenstein talked about not wanting to return null values but replacing them with empty arrays. I don’t recall ever learning about this, and they didn’t go into much detail about it, so I researched it a little further on my own. This podcast helped highlight the importance of refactoring and I’m sure I’ll continue to research more refactoring methods throughout my career.

https://fullstackradio.com/78

From the blog CS@Worcester – Derek's Design by dereksspace and used with permission of the author. All other rights reserved by the author.

It’s Easy to Break Promises

Context

I’m currently writing a Node.js package for a wrapper I’m calling a curfew-promise. It’s simpler than I thought, but it is still worth doing in my opinion. The package exports a single function that returns a promise. The promise has “3” parameters with the function header being: (curfew, func, ...args). The promise then performs func asynchronously (so func itself can be sync or async). It passes ...args to that function when it’s called. Lastly, the key idea here is that if func takes longer than curfew milliseconds to complete, the wrapper will become a rejected promise.

At first, it seemed like a tough task, until I discovered the built in Promise.race() function which creates a promise which we can refer to as the racePromise. That function then also takes in multiple other promises. Whichever passed in promise resolves or rejects first, its value is then passed onto racePromise. I can achieve my curfewPromise then by creating one promise that runs func and one that rejects after curfew has passed. Whichever finishes first becomes the value of the promise the function returned. The only way I’ve found to pause an async operation in JavaScript is via await new Promise((resolve) => { setTimeout(resolve, duration); }); This line, when placed into any async function, will pause operation until duration has passed. You can also remove the redundant brackets and shrink it down to await new Promise(r => setTimeout(r, duration)); , but I prefer to be more consistent.

JavaScript is NOT Multi-Threaded

JavaScript runs in a single thread. The way it pretends to be multi-threaded is by switching back and fourth between tasks to give all of them a little bit of time until they all finish. JavaScript is also an interpreted language. This means while trying to test my package, I had a lot of trouble. I spent a few hours trying to understand what was going on and now that I have, I’m going to write about it to save you trouble.

The Code

I was completely convinced that JavaScript itself was just broken. Here is my package, at least in its current state: (If you’d like to use this or see the modern version, check the GitHub page (soon to also be on npmjs.com))

module.exports = (curfew, func, ...args) => {
    let waitId;

    async function wait() {
        await new Promise((resolve) => { waitId = setTimeout(resolve, curfew); });
        return Promise.reject(new Error("Curfew of " + curfew + "ms have elapsed."));
    }

    async function perform() {
        const value = await func(...args);
        if(waitId) clearTimeout(waitId);
        return Promise.resolve(value);
    }
    
    return Promise.race([wait(), perform()]);
}

wait() creates a promise (using async notation, since from what I’ve read that is more ideal than direct promise notation) which waits until curfew has passed, which then rejects with a useful stack trace message. You’ll notice I’m also storing waitId, which is the ID of the setTimeout call. This way, if func finishes before curfew, I can cancel the timeout and not waste performance. I’ll also be looking into ways to create cancellable promises. I’m aware there are already packages that do this, but I think I’ll benefit from doing it by hand. I could make wait() a synchronous function that simply returns a waiting promise that calls setTimeout for reject, but I chose making it like this because then it matches the form of perform() (two async functions), and it allows me to write two lines that are visibly neat rather than trying to force everything into one line.

perform() creates a promise that waits until func is finished. Once it is, it’ll attempt to stop the waiting promise. If the promise is still waiting, it’ll stop it. If the promise has already rejected, it will do nothing. Then, the function returns a resolved promise with the value from func. I chose to write return Promise.resolve(value) instead of return value, which I understand to be the same thing, for consistency once again, and I think it makes the code more readable overall.

Lastly, I am creating the promises off of these functions and making them race. The function returns a promise that resolves or rejects whenever the first of the two – wait() and perform() – finish.

The Problem

I was able to narrow down the problem to this line:

        const value = await func(...args);

All of my tests had worked until I did something like the following:

const curfewPromise = require("./index");

// Broken Promise 1
console.log(curfewPromise(10000, async () => { 
    for(i = 0; i < 1000000; i += .001);
}));

// Broken Promise 2
console.log(curfewPromise(10000, async () => { while(true); }));

I found that for broken promise 1, despite the fact that curfewPromise returns a promise, it wouldn’t finish until the for loop finished. Even if I set the curfew to 0, it would take until the for loop completed. Broken promise 2 would never even end. I purposefully wanted to test these edge cases, where something would actually take a long time for ever (a good example for why I want the ability to cancel a promise).

The problem that I realized so frustratingly last evening is, and say it with me, JavaScript is NOT multi-threaded. Yes, when you run an asynchronous function, you can do other things in the meantime while it finishes. But as far as I can tell, JavaScript does this on a line by line basis. If you have a single line that is very slow or infinite, JavaScript will start running it, as that’s how asynchronous functions work, and then after some progress, it will move on. The thing is, you can’t make progress until that line ends. In the case of an infinite while loop, it will never end. In the case of a very slow one-line for loop, it can’t move on until the for loop is finished. Promise.race() cannot return a promise, so curfewPromise cannot return a promise. Once the for loop actually ends, it’s a gamble to decide which non-neutral-state promise will be chosen to have won the race. (Also keep in mind when using very small curfews, there is internal delay and it may not behave how you expect).

Conclusion

JavaScript is not multi-threaded. Make sure you keep that in the back of your mind. I was inadvertently testing for a case that shouldn’t ever even happen. While it was frustrating trying to figure out what was wrong, I still think that this kind of struggle is necessary in both life and learning. I always learn the most in coding when I’m trying to find out how to do something and I have 20 tabs open.

While this is a simple package that does something many developers probably can do easily, I still want to spend time making it and even upload it to npm. I think even though it’s simple, the function still helps clean up syntax to improve readability and reduce lines. I also think making it an external package helps to reduce complexity in your projects and helps me use it in multiple projects. Maybe someone can also look at it for help when learning how promises work.

At the end of the day, promises and asynchronous functions are an incredibly valuable tool in JavaScript and the illusion of multiple threads helps in most situations. Just be careful to not break your promises.

From the blog CS@Worcester – The Introspective Thinker by David MacDonald and used with permission of the author. All other rights reserved by the author.

Finding the Pattern in AntiPatterns

For this week, I will be discussing about anti-patterns. I chose to talk about anti-patterns because it relates to one of the topics on our course syllabus, and it seems like it would be good for me to connect and refresh concepts learned in the previous blog posts to anti-patterns; for many of the design patterns and software concepts learned are used to prevent anti-patterns.

To supplement my knowledge on this topic, I watched two youtube videos and read one article on anti-patterns. The first video I watched was a very short video about a developer who introduces the concept, anti-patterns. In the video, he connects anti-patterns to code-smells and basically says that code-smells serve to indicate potential/likely problems in your code, which are the anti-patterns. The second video I chose was lengthier and was by the infamous ‘techlead’, where he satirically talks about his favorite anti-patterns he has seen in his work experience. Although satirical, I was able to decipher why anti-patterns are important to catch and also was able to learn some anti-patterns from his talk. The third source, the article served to list more formal definition and examples of anti-patterns. The article referred anti-patterns as “… a literary form that describes a commonly occurring solution to a problem that generates decidedly negative consequences”. The article also listed examples of anti-patterns that were similar to the ones discussed in the techlead video.

I chose these three sources in that particular order because the intro video helped me better understand the general picture of anti-patterns, whereas the satirical anti-pattern video and the formal anti-pattern article helped to give more depth and understanding of anti-patterns. The satirical anti-pattern video also included real-world examples from an experienced developer which were helpful as well.

From all three sources I was able to consolidate a better understanding of anti-patterns and can see how they connect to previous material learned in my college courses. An important argument that caught me in the techleads videos was the importance of preventing/catching anti-patterns. He explains that antipatterns are dangerous because they are often irreversible and extraordinary hard to refactor once they are embedded into the architecture or code-base, and over time the damage accrues. In addition the anti-pattern article explains that anti-patterns are important to catch early because it may become a bad habit which will repeat itself. Many of the anti-patterns noted both in the anti-pattern video and article, pointed out common code-smells which appeared to be unnecessary-complexity and obscurity; which exemplifies the need for simple and readable code. This is also a common theme noted in the previous blog posts as well. One of the anti-patterns that I can relate to is the over-usage of refactoring, which is explained as bad because it slows-down readability of code during a code-review; yet it is taught extensively in some CS institutions. Overall, this topic made me realize the importance of learning proper usage of software design techniques and concepts in order to prevent anti-patterns in our code.

Sources linked below

https://www.javacodegeeks.com/2011/10/programming-antipatterns.html

From the blog CS@Worcester – Will K Chan by celticcelery and used with permission of the author. All other rights reserved by the author.