I just know that I have a history of trying to dive into a programming language and becoming frustrated at how stupid I feel when I hit a point that things just doesn't make sense.
I was reminded of this when working on a tutorial for making a very basic wiki using Go. It was a really good tutorial; step by step, it not only created a simple wiki server, but explained how it underwent an evolution.
Here's how, when we connect, this handler will stream these HTML instructions to the client! Now in this part, we'll take that text in the reply and change it to a template. Create a text file with this in it, and change the function so it calls the template instead. Same results, different method of getting them!
I carefully read the tutorial and implemented the instructions, with an occasional personalized touch just to test that I understood what was happening. And in the end I could say that I was able to trace out most of what it was doing. I was pretty proud of myself. But there were still limits to my understanding, and I found them most irritating.
For example, at the end of the exercise, there were "some simple tasks" to tackle on my own. They're good to do, since it demonstrates an actual understanding...to some degree...of the material. One of them involved creating a handler for people to connect to the web root and when they do, the server replies with a page called FrontPage.
I made the mistake of thinking to myself, "That shouldn't be too hard."
I trace out the execution path. Go makes the initial handling simple; in main() there's:
func main() {
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
http.ListenAndServe(":8080", nil)
}
The wiki lets you open pages using http://server/view, or /edit or /save, and anything else is a 404. This makes it kind of easy to decode what happens here. To create a handler for web root, I think, I just add a line for the root address to go to a makeHandler, which takes the actual handler (I'll explain in a moment) as an argument. Like this:
http.HandleFunc("/", makeHandler(frontpageHandler))
I also make a frontpageHandler function. To save redundant coding I just want to redirect requests to the web root to a page called FrontPage. Not overly efficient since it's a redirect, but I figure it shouldn't be a huge penalty for what I'm doing.
func frontpageHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/view/FrontPage", http.StatusFound)
}
This should pawn off the root page request to the /view hander. There's a problem though. The execution never gets that far. See, MakeHandler does, as was part of the tutorial, checking to make sure you are trying to access particular pages and nothing else.
func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
m := validPath.FindStringSubmatch(r.URL.Path)
if m == nil {
http.NotFound(w, r)
return
}
fn(w, r, m[2])
}
}
See that validPath.FindStringSubmatch, passing the URL? Yeah, that goes back to this:
var validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
And there's the stupidhammer hitting me in the head. It's REGEX! Now, seeing this, I can sort of tell what it's doing. The call in makeHandler will only pass on the request to edit/save/view handlers if the requested URL contains edit, save, or view, followed by a slash and an alphanumeric string. But how do I tell it to take a...nothing? Since I didn't know how to get regex to match just a slash alone...and I tried several variations only to fail each time...I was growing tired of hitting a wall.
Then I thought, "I would need to rewrite the request before it gets to the makeHandler! Then it'll pass the /view to the path!"
Only my attempts at that failed each time as well. I would have to change how the application pulls the variable assignment, since the URL that is analyzed for the existing code wouldn't be changed. Attempting to redirect prematurely seemed like it should work, but I couldn't get it to work in the initial handler in main().
I was getting a virtual bruise on my head before thinking, "Why pass it to makeHandler at all? I'm making a loop in the execution path anyway. It's not the most efficient or direct, but...it would work, wouldn't it?"
At this point I felt stupid for not understanding regex syntax well enough to just match a damn slash by itself (and my only solace was that at least I was aware of this limitation) but now I felt stupid for the amount of time it took before I thought of just bypassing the problem function.
So I made a change in main:
http.HandleFunc("/", frontpageHandler)
Now this created a new problem. It turned out that Go figured everything that matched with a slash would go to frontpageHandler, if it didn't match the edit/view/save handlers first. I didn't test if this was a cascade rules thing or not...I put the frontpageHandler at the bottom of the list of handlers, so if it was at the top, would everything evaluate to true for the slash first and never hit the save/view/edit handlers? I didn't test that. I was excited that it seemed to be getting a step closer to solving the initial "handle the web root request" goal. It did handle it! Only...it handled everything else you threw randomly at the server too. Whoops.
Next I figured my frontpageHandler needed to check that the request was truly for just the web root or return an error message. I went about making some changes:
func frontpageHandler(w http.ResponseWriter, r *http.Request) {
m := r.URL.Path
if m == "/" {
http.Redirect(w, r, "/view/FrontPage", http.StatusFound)
} else {
http.NotFound(w, r)
return
}
return
}
This seemed to do it. Now if you request the web root, it returned FrontPage, using the existing code paths via a redirect to /view. If you requested something like http://server/letsfeeditrandomtrash, you 404'd.
This seems to work. It seems to fit the criteria. But I still feel like I'm mentally defective because I know that programmers like Matt Sherman and Matt Jibson wouldn't have solved the problem this way. They probably would have bypassed the whole problem by knowing the regex off the tops of their heads, and my solution was an inefficient hack.
It's times like this that I feel an overwhelming grasp of the divide between, "I made this work as requested!" and "This was a horrible hack, nowhere near up to quality standards that I want it to be." And worse, I feel like I'm missing the ability to figure out how to bridge that gap.
I look at the source code for the tutorial and think to myself that I understand most of it. I miss some details...why does this look like it's passing by reference, or why is this looking like a pointer...but I get the gist of what's happening and am able to trace what is going on (otherwise I'd be still figuring out why my frontpage function is 404'ing and missing entirely that validation check.) I also understand that if I were coding the wiki example from scratch, a lot of this approach to making the wiki I would have missed. I wouldn't have thought to use the regex patterns for validating the input. Many of these functions I wouldn't have thought to use; I'd still be looking up what the libraries in question can do. I mean...a function that takes a function as an argument then returns that sub-function to the appropriate function after evaluating if the initial call is "valid" via the URL? The final tutorial version even does a sweep of the template files and reads them in as a variable that is referenced instead of individual calls to pull a template during runtime. I doubt I'd have thought of that.
So at this point I feel stupid because I couldn't figure out the proper regex...my solution was a horrible hack...and looking at the existing code, I wouldn't have thought of doing it this way if I were left to my own devices. The distance between where I was and where I'd want to be in competence is a gap larger than any ladder I imagine having in my possession.
At the same time I know that if I call it quits, I'll end up trying something again later. Maybe it would be an idea for learning Ruby on Rails. Maybe it'll be picking up Go again. Or Visual Basic. And I'll bang my head on the same limitations, but with a sliver more familiarity. It's happened before. Several times. Hence...here again. Same crossroads.
Perhaps coincidentally I saw a post on Reddit at approximately the time I was having this crisis in faith from a person who developed an iOS game and had virtually nil sales after starting his programming journey two years ago. A lot of people bitched that he was just trying to market his application, and mods removed the post eventually, but he insisted he was trying to talk about the process he went through in creating the application. I found that part interesting. Part of what he said:
A few weeks ago I released a game in the iOS AppStore called “Inject”. In 2012, I had this game idea/mechanic in my head that I thought was pretty cool – To use a touch screen to simulate an injection mechanism. At the time I didn’t know a single thing about programming or game development but the dream seemed possible. And so I decided to try. I struggled to learn how to program to bring this game to life. It was brutal. I wasn’t built to program things. Codeacademy lies. Not everyone can code. But in the end, I finished.
He also said,
I used Code Academy just to learn how languages work. I seriously had ZERO background in anything to do with programming. I was always bad at math. I even suck at most games but I like playing them.
I think once you understand how computer languages in general work. (you only need a really superficial understanding). You can then chose a language that you want to focus on and look up tutorials for that language/framework to build what you are trying to build. So if you're trying to make something for iOS look into obj-C /cocos if you have big balls. Or for something more newb friendly like game maker/stencyl etc.
I suppose I can also keep struggling to make this work. I used to say that each small step was still a small step forward. I'll keep trying to make tiny steps forward to see what I can make.
Now...I'm off to find a good basic tutorial on HTML. Those templates don't magically work on their own, after all.