Tooling Not Craft

For a while, I’ve had the nagging feeling that there’s something missing with the way that many junior developers learn to write software these days. In a way that I suppose makes me a bit of a curmudgeon, I somewhat long for the days before the prevalence of the IDE and the automated unit test framework.   But rationally I know that IDE’s and other specialized tooling have done a lot to both cut grunt work and to eliminate accidental complexity so it’s hard to deny they’re a big step forward from what came before.

And then it occurred to me.  Some of my issue with the modern tendency toward doing everything in the IDE is the tendency that weaker developers have to conflate tooling with craft.  Because Eclipse has the ability to automatically generate getters and setters for each data member of a Java class they simply stop questioning the wisdom of having getters and setters for all the members and merrily march forward–exposing far more data than they should.  The benefit of data hiding, which, after all, was the original benefit of private class members is largely lost because they can’t be bothered to actually think through the wisdom of effectively turning a class into a pseudo-struct.

A long time ago when I first began coding I had a senior developer who mentored me.  I had a bit of a tendency to charge in and start changing code (I am still guilty of that I suppose) without really thinking through the problem.  He wisely counseled me to take a few minutes to think about the problem before I started hacking.  Now I think I understand how he felt.

Don’t get me wrong–better tooling is definitely a good thing.  But don’t let your tooling dictate your craft. And if you want to be a truly better developer focus on learning the craft of building strong code.  The tooling is important, of course, but the underlying craft is much more important.

Some Updates On “LDAP Authentication With Phoenix”

There’s an excellent write-up on authenticating users against an LDAP database with Phoenix which was created by Richard Nyström.  For some reason even though it’s barely a year old, there seem to be a few points that are either out of date or simply incorrect. I worked through his example and I wanted to share a few amendments to his original code in the interests of other developers who may want to use LDAP with Phoenix.

First the set up of Phoenix


mix phx.new ldap_example # was mix phoenix.new ldap_example
...
Fetch and install dependencies? [Yn] Y

cd ldap_example

mix ecto.create (configure your db in config/dev.exs if needed)

mix phx.gen.schema User users username:string name:string email:string
# was
# mix phoenix.gen.model User users username:string name:string email:string

mix ecto.migrate

Next change is in the session_controller.ex file:


#was LdapExample.SessionController

defmodule LdapExampleWeb.SessionController do

#was LdapExample.Web, :controller

use LdapExampleWeb, :controller
alias LdapExample.{User, Repo, Ldap}

def new(conn, _params) do
render conn, "new.html", changeset: User.login_changeset
end

def create(conn, %{"user" => params}) do
username = params["username"]
password = params["password"]
case Ldap.authenticate(username, password) do
:ok -> handle_sign_in(conn, username)
_ -> handle_error(conn)
end
end

defp handle_sign_in(conn, username) do
{:ok, user} = insert_or_update_user(username)
conn
|> put_flash(:info, "Logged in.")
|> Guardian.Plug.sign_in(user)
|> redirect(to: page_path(conn, :index))
end

defp insert_or_update_user(username) do
{:ok, ldap_entry} = Ldap.get_by_uid(username)
user_attributes = Ldap.to_map(ldap_entry)
user = Repo.get_by(User, username: username)
changeset =
case user do
nil -> User.changeset(%User{}, user_attributes)
_ -> User.changeset(user, user_attributes)
end
Repo.insert_or_update changeset
end

defp handle_error(conn) do
conn
|> put_flash(:error, "Wrong username or password")
|> redirect(to: page_path(conn, :new))
end

def delete(conn, _params) do
Guardian.Plug.sign_out(conn)
|> put_flash(:info, "Logged out successfully.")
|> redirect(to: "/")
end
end

The changes to user.ex are not made in the web/model/user.ex; rather they’re made in the existing user.ex file.

And finally a change to session_view.ex

#was LdapExample.SessionView

defmodule LdapExampleWeb.SessionView do

use LdapExampleWeb, :view

end

Win Tickets To Detroit.Code

I am very excited to be helping with the inaugural Detroit.Code conference here in July 2017.  In fact all of us that work on the DetroitDevDay conference are very excited about this new conference.  We all support growing the metro Detroit software development community and this is another great step in growing that community. (Full disclosure: I am speaking at Detroit.Code.)

As such we want to help make sure as many folks get to the conference as possible. So we’re going to give away a couple of tickets to the event. However, we want to have a little fun at the same time.  So we’re also going to run a little coding contest; everyone who gets the right answer on the coding contest will be entered into a drawing for the two tickets we’re giving away.

I have no interest in spamming folks with the details of the coding contest so if you’re reading this and you’d be interested in getting into the contest, please send me an e-mail at catenacci@ieee.org (gad I’m sure to have more spam soon) and I will add you to the list of folks who get the coding challenge.

Code And Coffee

I’ve always admired something that my friend @CarinMeier mentioned that they do down in Cincinnati (or at least they used to do it anyway).  That’s  a once-monthly “Code And Coffee” where people would get together at a local coffee shop to drink coffee and learn about some interesting topic.

I’m going to be at the Biggby Coffee in Clawson (on 14 Mile) on Wednesday May 3, 2017 at 7 am.  If you’re reading this blog post consider yourself invited to join me for some coffee, some shop talk, and likely some coding.  If you want to join, feel free. People who know me will probably guess that I’m likely to talk about functional programming but honestly I’m willing to talk about almost anything technology related.  If you do decide to join, bring a laptop.

Left Side vs. Right Side Agile

We were discussing agile today and I came up with something that I thought might be worth sharing with others.

Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan

And I was saying to some of the folks on my team that it seems as if we’re getting right side agile and not left side.  While lots of firms these days are calling themselves agile they’re still very much on the right side of that list. As someone put it to me, lots of places are doing waterfall with daily stand ups and two week sprints.

So maybe we need to start calling out our managers and our VP’s on right side agile and tell them that we favor the left side and we want them to favor it too.

Premature Generalization

I’m sure most developers reading this post will be familiar with the term “premature optimization”. For those who may not be familiar, this refers to the tendency that some developers have to worrying about the performance of their code, usually but not always in terms of execution time, before their code is proven to work correctly in terms of customer requirements. It’s like saying, “Hmm, this function call may take 3 clock cycles to execute but if I inline the code it won’t take any extra clock cycles” before the developer has correctly defined the function to be called. It’s generally considered a poor way to write software. I believe it was probably Joe Armstrong, one of the co-creators of Erlang, who said “Make it right, make it fast, then make it pretty.” Getting the code right always comes before any sort of optimization should be attempted.

Risking the perils that may befall anyone who coins a neologism, I propose another premature condition which developers should try to avoid: premature generalization. I would define premature generalization as being the tendency to assume that what you see or what you want is what every other developer sees and/or wants. It’s the tendency of the novice developer to post messages like “Hey function x isn’t working. What’s wrong?” assuming that the rest of us also have the problem they have and we therefore don’t need any more detail to know what he or she is talking about. It’s also the tendency to assume that because they need to address some particular use case that most developers working in the language will need to address the same use case: “Hey I need library function x to return an error status when I pass it a bad argument but throw an exception when I pass it a good but out of range argument. Can we modify the standard library to do this?” In both cases, I believe they’re prematurely assuming their question is generic and therefore they don’t need to provide details to others.

Although I feel I’m flogging a dead equine I hasten to point out that as software developers we should usually proceed from the assumption that the error we’re seeing is due to something specific to us. We should also proceed from the assumption that any use case we have is likely to be a use case specific to us until we see evidence otherwise. Yes, I am aware of the irony of making generic statements here—but given what I’ve seen over 25+ years of software development I don’t believe that I’m indulging myself in premature generalization.