<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sam Fisher</title>
    <description>The latest articles on DEV Community by Sam Fisher (@swfisher).</description>
    <link>https://dev.to/swfisher</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F115425%2Fa08aedf7-ac09-46c8-8ad6-1f5656096cf8.JPG</url>
      <title>DEV Community: Sam Fisher</title>
      <link>https://dev.to/swfisher</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/swfisher"/>
    <language>en</language>
    <item>
      <title>Why I Study Computer Science as a Self-Taught Developer</title>
      <dc:creator>Sam Fisher</dc:creator>
      <pubDate>Fri, 15 Mar 2019 06:12:40 +0000</pubDate>
      <link>https://dev.to/swfisher/why-i-study-computer-science-as-a-self-taught-developer-m33</link>
      <guid>https://dev.to/swfisher/why-i-study-computer-science-as-a-self-taught-developer-m33</guid>
      <description>

&lt;p&gt;Today I asked myself the question: Now that I've established the beginnings of a career in programming, what is my motive for continuing to devote time to studying computer science? &lt;/p&gt;

&lt;p&gt;Here is my answer: &lt;/p&gt;

&lt;h2&gt;
  
  
  The joy in programming is about craft.
&lt;/h2&gt;

&lt;p&gt;Craft is a deep topic in and of itself. For now, let's say that it has to do with the intrinsic reward of a thing done in it's own right. Craft relates to that universal appreciation for the beauty of a thing done well. &lt;/p&gt;

&lt;h3&gt;
  
  
  Depth
&lt;/h3&gt;

&lt;p&gt;I think it's great that you can go a long way into the field of programming without ever touching the theoretical aspects. That makes room for bright, talented new people from all kinds of backgrounds to join in a fairly lucrative and deeply rewarding field.&lt;/p&gt;

&lt;p&gt;However, to develop a truly justified confidence in one's software design choices, a developer needs to see past the surface of the field and into its depth. It would be impossible for any craftsperson to really enjoy their work fully without an informed degree of confidence in the the quality of the results. &lt;/p&gt;

&lt;p&gt;One could learn the basic syntax of a dozen programming languages and work on a slew of different web applications over the course of a decade all whilst remaining eternally a novice. Depth is the precise difference between this person and someone who demonstrates authentic understanding and lucid competence in their design choices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tangibility and Abstraction
&lt;/h3&gt;

&lt;p&gt;Many programmers get hooked into the field by the awesome reward of getting a simple program to work and produce a satisfying result. The tangibility and immediacy of this makes programming accessible and fun. It's a great help to us.&lt;/p&gt;

&lt;p&gt;However, to really understand programming we also need to develop a taste for understanding it as a fundamentally abstract mental discipline. This is really the evolution from "coding" to "software design." The reward in that mental discipline is different from the fun of getting a neat result quickly. It's a much slower and more profound reward that is characterized by the feeling of truly grasping a beautiful or interesting idea.&lt;/p&gt;

&lt;p&gt;A programmer engaged in software design (which is, by definition, any programmer) is a very interesting kind of craftsperson. This is a craftsperson whose design artifacts hang somewhere between the abstract and the concrete. The programmer both embodies theoretical models in concrete form (coding) and distills theoretical models from some less precise set of ideas (software design). The need to morph between different ways of thinking leaves the programmer with much to do and learn in this life, but isn't that kind of challenge exactly what we like?&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspiration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.amazon.com/Craftsman-Richard-Sennett/dp/0300151195"&gt;The Craftsman by Richard Sennett&lt;/a&gt;&lt;/p&gt;


</description>
      <category>computerscience</category>
      <category>opinion</category>
      <category>philosophy</category>
      <category>ramble</category>
    </item>
    <item>
      <title>A Philosophy of Software Design, Part 0: Introduction</title>
      <dc:creator>Sam Fisher</dc:creator>
      <pubDate>Sat, 17 Nov 2018 23:52:04 +0000</pubDate>
      <link>https://dev.to/swfisher/a-philosophy-of-software-design-4gdl</link>
      <guid>https://dev.to/swfisher/a-philosophy-of-software-design-4gdl</guid>
      <description>

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; This series of articles is a living document in a continuous and unpredictable release cycle. I modify it when I have time and inspiration. It serves the purpose of helping me understand and share the ideas that are primary to my understanding of our craft. Feedback will definitely be considered and appreciated.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The right question at the right time leads to a natural and vigorous effort." - George Polya&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As software engineers, we'd love to be in an endless flow of movement towards precisely the right outcome at each point in time. We'd love to enjoy our work fully, to deliver great products, and to consistently grow as craftspeople. But how do we ask the right questions that inspire the right actions at any given point in time? How do we structure our effort? &lt;/p&gt;

&lt;p&gt;We don't really know the answer to these questions, no matter what tools or principles we use to help us navigate. Some such ideas are written down and understood; some are just subconscious tricks we aren’t even aware of. &lt;/p&gt;

&lt;p&gt;As generations of software engineers have reflected on their work, a handful of global strategies for software design have emerged and been made explicit. The code of these strategies reflect universal principles of mathematical problem solving and have meaningful analogs in all branches of science and engineering. &lt;/p&gt;

&lt;p&gt;Masterful practitioners tend to know these strategies on an intuitive level. For some it can be hard to verbalize the tools that are well-integrated into their body of tacit knowledge. This means that beginners can be left grappling for useful language about why particular software designs are good or bad. &lt;/p&gt;

&lt;p&gt;As beginners, we can seek to integrate good design principles into the intuition that guides our everyday practice. Having an explicit verbal representation of such principles is only a pointer towards developing insight. Ultimately, it is your intuition that has to do the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Idea of Good
&lt;/h3&gt;

&lt;p&gt;As a whole, designing software is about studying the natural structure of abstract problems and expressing that structure simply and beautifully. The question is always "how do we reach a simple understanding of the problem and reflect that understanding in the design?" But why simple?&lt;/p&gt;

&lt;p&gt;The closed and predictable nature of software always exists within an open and changing human context. The criteria for simplicity emerges because software succeeds or fails by its ability to gracefully manage human limitation. &lt;/p&gt;

&lt;p&gt;Is the codebase intuitively beautiful to programmers?&lt;/p&gt;

&lt;p&gt;Could we easily integrate its functionality with a new idea? &lt;/p&gt;

&lt;p&gt;Can we easily change how a part of it is implemented?&lt;/p&gt;

&lt;p&gt;Does the system perform seamlessly for end users? &lt;/p&gt;

&lt;p&gt;Is the system's functionality immediately understandable to end users?&lt;/p&gt;

&lt;p&gt;And so on... &lt;/p&gt;

&lt;p&gt;The following ideas should help us with all of these objectives at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Principles for Good Software
&lt;/h3&gt;

&lt;h4&gt;
  
  
  (1) Simplicity
&lt;/h4&gt;

&lt;p&gt;Simplicity, in this context, means focus on one thing. One fold. One problem. One responsibility. Simple ideas fit easily and compactly within our cognitive limitations. Reaching simplicity enables you to reason about the problem with fluency and ease. When we understand a subject well, our understanding becomes simpler. This being said, simplicity takes effort.&lt;/p&gt;

&lt;p&gt;What is complexity? Let's decide that it means focus on many things. Many folds. Many problems. Many responsibilities. This is a convenient definition for us. It's clear that a complex thing is actually composed of many simple things.&lt;/p&gt;

&lt;h4&gt;
  
  
  (2) Modularity
&lt;/h4&gt;

&lt;p&gt;Divide any complex problem into a set of small ideas that most easily and naturally express the complete picture. In programming, each small problem is often solved by one "module" of the system. This has myriad benefits, but most prominently it allows you to focus on one aspect of the problem at a time. As a problem solving strategy, this is sometimes called "Divide and Conquer."&lt;/p&gt;

&lt;p&gt;Allow each module to take on its own identity rather than relying on an external context to make sense. A square is just a square. A random string generator is just that. Deliberately avoid entangling the modules with their context, as this creates complexity. This strategy is called "decoupling", or taking apart what was once tied together.&lt;/p&gt;

&lt;p&gt;Use good names for your modules that clearly distinguish what they are. These names will serve as the one word summary for calling that module to mind. Creating simple names for meaningful groupings is called "Abstraction." By creating a word for something, we can  stand back and describe it from a bird's eye view. We now have a nice coat-hanger in our memory that we can use to recall the details when we need to.&lt;/p&gt;

&lt;h4&gt;
  
  
  (3) Minimality
&lt;/h4&gt;

&lt;p&gt;There are many possible collections of simple modules we could use to solve a complex problem. How do we choose a good collection? &lt;/p&gt;

&lt;p&gt;We choose the smallest set of modules that result in the broadest set of functionality. In other words, we search for maximum leverage with minimum effort. We'll call this ideal state "minimality." A successful modular approach to reaching simplicity has minimality. Minimality is achieved by discarding complexity  in our understanding of the problem without losing information.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;em&gt;(a) Self-Similarity&lt;/em&gt;
&lt;/h5&gt;

&lt;p&gt;Very often, problems contain hidden redundant information. Consider the way shapes that are symmetrical can be divided into two identical sub-shapes. When self-similarity in the problem exists, you can always abstract away the unchanging aspects to simplify your understanding. &lt;/p&gt;

&lt;p&gt;This often arises in programming in the form of 'recursive objects' like sets, arrays, graphs, strings etc. All of these common structures are made up of smaller instances of that structure and have a smallest possible version. When a recursive structure or algorithm is chosen, a programmer looks at the problem and sees the self-similarity echoing through the complexity. For a classic example of a recursive solution, check out the "Tower of Hanoi."&lt;/p&gt;

&lt;p&gt;Another way self-similarity expresses itself in computer programs is the folding of unchanging factors in a calculation away from program logic and into data. This is called proportionality. If some aspect of a computation is the same for every element in an iterative process, it makes sense to abstract this away. This has the dual effect of making the program easier to reason about and faster to run.&lt;/p&gt;

&lt;p&gt;Lastly, we can know that the language and tools we are applying to the problem are unnatural and unhelpful if they do not immediately suggest meaningful self-similarity. There are infinite ways to divide and conquer a problem, and if our strategy does not reflect the natural shape of the problem then it will tend to obscure rather than reveal the inherent recursive structure living inside it. Finding and honoring self-similarity in a problem leads to "a-ha" moments because it brings us directly to simplicity.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;em&gt;(b) Orthogonality&lt;/em&gt;
&lt;/h5&gt;

&lt;p&gt;Separation is how simplicity expresses itself in problem decomposition. When two spaces are orthogonal, it means that they are perpendicular to one another and therefore have only a single point of intersection. &lt;/p&gt;

&lt;p&gt;Orthogonal entities can evolve independently from one another. They also have perfectly minimized redundancy in information since they have nothing in common. Finally, they have maximal combined “bang for buck” because two independent things can be combined in more ways than two dependent things.&lt;/p&gt;

&lt;p&gt;As a rough but fun analogy for this concept, consider that I can do more with a cup and a knife than I can with two cups. Cups and knives both have useful functionality, but the cup and the knife have much less in common with each other than the two cups. &lt;/p&gt;

&lt;p&gt;Imagine that instead of an orthogonal cup and knife, I designed a cup and knife hybrid. My cup-knife will be full of compromise between disparate concerns. It will be less effective at facilitating both cutting and drinking. At best, it will represent two unrelated bodies of functionality uncomfortably sharing space.&lt;br&gt;
This entanglement creates unnecessary complexity.&lt;/p&gt;

&lt;p&gt;The orthogonal modules you design should also be simple. A simple module will have a natural clarity of expression, testability, and reusability because of its singular focus. If a module in your design turns out to be complex, you can reduce it into two or more orthogonal pieces. These will be easier to create, evolve, and connect than two entangled pieces.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;em&gt;(c) Generality&lt;/em&gt;
&lt;/h5&gt;

&lt;p&gt;Can we broaden the problem we're solving without adding dimensions to it? Does taking away unneeded details help it to take on a clearer form? Generality is achieved by such insightful subtraction and summarization.&lt;/p&gt;

&lt;p&gt;We started out by thinking very close to the problem's nature. This might leave us with a design that reflects a narrow case of a more general problem. If we allow our model of the problem to cast off the trappings of the domain in which it arose, we can achieve functionality that exceeds the initial expectations while growing simpler in its nature. If the scope of  work grows when you try this, then you've probably added an extra dimension to the problem. If it shrinks, then you've probably removed some arbitrary specificity from the model and moved towards minimality.&lt;/p&gt;

&lt;h4&gt;
  
  
  (4) Composability
&lt;/h4&gt;

&lt;p&gt;All these tidy, independent modules we're creating need to communicate well or else they won't help us solve the problem. Additionally, we can gain a tremendous amount in generality if our modules can communicate with other systems we haven't thought of yet. Clean interfaces for your modules allow them to accomplish both of these goals.&lt;/p&gt;

&lt;p&gt;Composability is the measure of how simple it is for any given system module to act on the output of a different module.&lt;/p&gt;

&lt;p&gt;Optimizing for composability involves tradeoffs in coupling and decoupling modules. The design of REST, a style of networked application architecture, constrains an API to have a uniform interface for any and all client applications. This creates huge gains in composability at the cost of some performance optimizations that might have come from tightly coupling the interface to a client. The minimum we can do is to take free gains in composability whenever they are available. The maximum we can do involves compromise with other desirable qualities.&lt;/p&gt;

&lt;p&gt;When possible, favor simple and universal formats for input and output. Provide the least surprising developer experience when interacting with the module. Use names that succinctly describe each module's point of singular focus. Good names are a starting point for code that makes your understanding of the problem immediately visible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Towards a Process for Good Software
&lt;/h3&gt;

&lt;p&gt;Where does that leave us? We've identified some core principles of good software design, but these principles only go so far in telling us explicitly how to structure our time and effort.&lt;/p&gt;

&lt;p&gt;In my view, creating software is a discipline of problem discovery and decomposition. In the coming articles I'll lay out a fairly universal model for designing software based on the principles discussed above. I'll derive the skeleton of the process from a generalized problem solving approach known as "Polya Problem Solving", outlined in George Polya's book "How to Solve It." Each article will tackle one stage of the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Outline for our Process
&lt;/h3&gt;

&lt;p&gt;1) Understand the Problem - Discovering and defining requirements&lt;br&gt;
2) Design a Solution - Articulating a system design&lt;br&gt;
3) Implement the Solution - Partitioning work intelligently&lt;br&gt;
4) Learn from Reflection - Using self assessment and extension&lt;br&gt;
5) Learn from Contact with Reality and People - Using measurement, delaying optimization, and adapting to surprises&lt;br&gt;
6) Iterate Forward - Maintaining robustness and scalability inside of a changing context.&lt;/p&gt;

&lt;p&gt;Each phase has a risk of being incomplete or going on for too long, and requires good heuristics for deciding when to move forward. More formally, each phase transition in our sequence is an instance of an optimal stopping problem. The work is usually never perfect and never done.&lt;/p&gt;

&lt;p&gt;Next up, we dive into Part 1: Understanding the Problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspirations
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ocw.mit.edu/resources/res-6-011-the-art-of-insight-in-science-and-engineering-mastering-complexity-fall-2014/online-textbook/MITRES_6-011F14_art_insfin.pdf"&gt;The Art of Insight in Science and Engineering - Sanjoy Mahajan&lt;/a&gt;&lt;br&gt;
&lt;a href="http://www.catb.org/esr/writings/taoup/html/"&gt;The Art of Unix Programming - Eric Raymond&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pragprog.com/book/tpp/the-pragmatic-programmer"&gt;The Pragmatic Programmer - Andrew Hunt and David Thomas&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf"&gt;Architectural Styles and the Design of Network-based Software Architectures- Roy Fielding&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.educative.io/collection/5668639101419520/5649050225344512"&gt;Grokking the Systems Design Interview - Design Gurus on Educative.io&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/How_to_Solve_It"&gt;How to Solve It - George Polya&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.penguinrandomhouse.com/books/312435/a-beautiful-question-by-frank-wilczek/9780143109365/"&gt;A Beautiful Question - Franz Wilczek&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Special Thanks
&lt;/h3&gt;

&lt;p&gt;Andy Pickle, for convincing me to write on dev.to&lt;br&gt;
Ry Whittington, for pointing out a crucial typo (see discussion below)&lt;/p&gt;


</description>
      <category>softwarearchitecture</category>
      <category>systemdesign</category>
      <category>metaprogramming</category>
      <category>problemsolving</category>
    </item>
  </channel>
</rss>
