Saturday, August 31, 2013

import != #include

I spent my summer doing software development for a local company and most of what I did was structural work on a large C++ code base with a long history. Since I am teaching a data structures course this coming fall that will use C++, I figured it would be good experience. It certainly gives me some stories to tell, but it has also helped to bring into sharper relief the differences between C++ and Java (as well as all the languages that have been influenced by Java).

I will write another post giving more of my thoughts on C++11, but I should mention right off the bat here that I think C++11 has a lot of really cool features that greatly improve the language. Developing modern code in C++ is not a bad thing, but the legacy of C++ means that not all code written today has to use the modern style, and worse, the code currently in existence doesn't use these features at all. Plus, even with the improvements C++ still uses pretty much the same tool chain as C and that is a bit of a problem.

How They Differ

I've always known that import and #include do different things. I make sure to point this out to students any time I am teaching a class where I can compare languages that use these two different features. However, working on a large C++ code base made the difference really stick out. What I came to realize is that #include causes a problem because it impacts the structure of code. This isn't an issue with import because it does nothing more than tell the compiler how to resolve short names in a source file into fully specified names.

The difference becomes more obvious when you run into situations where the order of #includes in a source file is important. I have to point out that if one follows all the normal best practices this never happens. Unfortunately, not everyone has followed these practices. In particular, there are Windows libraries that do things which break the rules and cause the order of includes to matter. The Windows libraries also have odd behaviors where you aren't allowed to include some files directly because they depend on other things being defined first. This can be particularly challenging when you are working on a project and the IDE tools do a great job of telling you exactly what header file defines something you need, but you aren't allowed to include that file because Microsoft did something non-standard in building their libraries. (This comes up a lot with their typdefs of BOOL, TRUE, and FALSE. That topic is probably worth a whole blog post to rant about.)

In some ways, I feel that the real problem is that header files can, and often must, include other header files. Because of this, putting a single #include in a source file can result in 100 or more other headers being included. Mix in a few #ifdef or #ifndef directives and things quickly become a complete mess where order matters a lot.

How This Happens

Now it is easy to throw stones at previous developers (including those for Windows) and say they just didn't know what they were doing. Inevitably there are situations where previous developers made some poor decisions that led to structural code problems in the headers. However, many of these things can creep into code over time and maintenance programmers can easily add them in not realizing what they are doing. The reason is that some flaws in code related to #includes and headers are hard to track down unless you have a powerful static analysis tool to help you. For example, files should #include all the things that they use and not things that they don't. Sounds like a simple enough rule to follow when you are the original author of a file. The compiler won't like your code if you don't #include things you are using, and unless you just have a bad habit of adding lots of #includes at the top of every file because you "might use them" you aren't going to put in extra stuff.

However, even with the original author there can be some challenges if you rely on the compiler to tell you when you are including everything that you need. If you have one header file that includes a lot of others, it is possible you might include that one file and forget to include the others directly even though you use things in them. This doesn't sound like a problem until you, or someone else, makes a change in what that one header file includes and your source files break because it wasn't doing its own includes directly. Relying on one file to do things for you that aren't really part of its job description is generally a great way to give yourself headaches later on.

When you consider the situation of the maintenance programmer, things get much worse, especially if the code was a bit smelly to start with. It is easy to add code and just say that if it compiles everything is happy. It takes time and effort to go to the top of the file and see if there is already a #include for the things you just added in. The time and effort grow if the file is longer than it should be. Not only do you have to jump farther from your current editing point to check, but the length of the #include list generally grows as well.

The problem is even worse when you are deleting a function, method, or even a few lines of code. Figuring out if you just deleted the only reference to something in a particular #include is not a trivial task. As a result, #includes, once added, are unlikely to never go away until someone decides to spend some real time doing cleaning or if you have a static analysis tool powerful enough to tell you that some particular #include is no longer needed.

It Made Sense for C

So why was such an odd system put into place to begin with? Well, it made sense for C, which ran on limited systems and very strictly followed the requirement of everything happening in a single pass. There were lots of hardware reasons why the original C compilers needed to go through their programs in a single pass from top to bottom and not store lots of extra tables for things along the way. When your program is stored on a tape (or punch cards) and your machine has limited memory, you don't want to have to run through the source multiple times in the process of compiling.

What changed?

Of course, most of those reasons are completely moot on a modern machine. This is why we have seen a march of programming languages that move more and more of the work onto the compiler. Focusing on Java, the import statement doesn't actually do anything to the code, it just tells the compiler how to resolve short names into the longer, fully specified names that they represent. (Honestly import is really the equivalent of using in C++, not #include.)

Faster machines with more memory and the fact that you were never compiling something stored on a tape made multiple passes and random access far more acceptable. So you don't have any need to have the preprocessor spit out something that can be handled in one pass from top to bottom. You don't mind if the compiler has to go looking in separate files. In fact, that can be faster. The whole idea of precompiled headers in C and C++ only exists because opening and processing the same header files over and over for every source file in a large project can really slow things down. Losing the concept of a header file removes that overhead from the compiler. (I also really appreciate that it removes code duplication. Having to touch two files any time a function signature is adjusted has always annoyed me.)

Making import work

In Java, a significant piece of what made this possible working with the computers available in the mid 90s was that there were very specific rules that had to be followed related to file names and directories. The fully specified name in Java tells the compiler exactly where it should go looking for something. So all the compiler has to do is figure out the fully specified name and that is exactly what import statements do in the code, allow short names to be turned into fully specified names.

Newer languages have relaxed some of Java's strict naming rules and have put even more burden on the compiler. Scala comes to mind as a key example of this. It compiles to the JVM and the .Class files are placed in the restricted directories required by the JVM, but the compiler actually takes its cues from the source code. Of course, it is generally recommended that you follow the Java scheme because it makes it easier for programmers to find where things are as well.

Conclusion

My main conclusion from all of this was that the decision to leave behind #include semantics and switch to import semantics was a huge step forward in programming. I know that I first saw import in the Java language, but I expect that it dates back to something earlier. Perhaps someone can leave a comment on the origin of import semantics.

Tuesday, August 27, 2013

Why does Klout undervalue Google+

Let me start off by saying that I'm a fan of Klout. I think that they are a very interesting metric of social network activity. I like the idea of an attention based economy and I think that Klout is a potential model for how that could begin. Plus there is the Scala factor. Given the I am a Scala zealot I love that Klout not only uses Scala but that they write about it in their engineering blog. I think they give great publicity to the language. I am also very much looking forward to having Klout include other networks in their scores. Specifically, I would love to see the inclusion of YouTube and Blogger.

Having said all of that, there is one thing that has been really bothering me. I feel that Klout dramatically undervalues Google+. To illustrates this we can look at the my profile and the network breakdown on Klout.


You can see that Klout says that most of my score comes from Facebook followed by Twitter and then Google+ right behind that. They also provide some summary information for what they base this on including friends, followers, and interactions on the different networks.

One of the things that Klout isn't showing under the Network information is how many people have me in circles on Google+. I find this very odd given that they do list number of friends for Facebook and number of followers on Twitter. So you can see in the figure above that I have less than 200 Twitter followers and under 600 Facebook friends. To compare this to Google+ I've included my CircleCount page here.


You can see from this that I have over 8,500 followers on Google+. I'll be the first to admit that I don't have a lot of engagement with the vast majority of those followers, but I typically get 10+ notifications of some type of engagement every day. I probably get a bit more engagement on Facebook, but I have much, much less on Twitter.

So my question is, why does Klout say that Twitter is slightly more significant than Google+ and that Facebook is more than 6x as significant? Is there something about the API that Google provides that prevents them from getting the needed data to consider Google+ appropriately or is their formula simply messed up? I'm hoping someone working at Klout might see this and comment. Maybe even look into it and consider tweaking that part of their formula in the next major revision. I realize it is very hard to compare across networks and that probably leads to differences, but this seems a bit extreme to me. I also feel for the Klout developers as they look at how to integrate Blogger, YouTube, and others.

Tuesday, March 19, 2013

Why coding isn't like working a printing press

Yesterday I was in a meeting with other STEM faculty discussing the proposed new curriculum for Trinity. Toward the end of the meeting I turned the discussion toward the Digital Literacy Competency aspect of the proposal. I was on the committee that created the original version of that proposal, and I felt that it had been watered down a bit. In particular, the term "algorithm" had been removed. The goal that I have for that part of the curriculum is to make it so that every student graduating from Trinity has written a little code to solve a problem. There are lots of places where people have argued for the importance of this. Some of my favorites are the blog post "Should you learn to code?" and the videos at Code.org. (If you haven't seen these PLEASE take a minute to look at them. Technically it will be 5 minutes for the normal version of the Code.org video.)

What really surprised me at this meeting was how many of the STEM faculty were opposed to this idea. I used the analogy of code being a new form of literacy and a few people commented how they didn't know how to use a printing press. Later that night I realized what I should have said in response to that to illustrate that coding is nothing like being the person who runs a printing press. Here are some reasons. First, you aren't surrounded by printing presses. You are surrounded by computing devices, just like you are surrounded by books. Second, running a program someone else wrote is, at best, like reading a book. You are consuming what someone else produced. I don't think any of my peers would argue that we would be happy having students who can only read and consume written information, but are incapable of writing their own. The goal of this capacity is to give students the first glimpses of how they produce in the digital world. If you have never seen programming, you are stuck as a consumer. You can't produce anything on the devices that surround you every day.

Note that I'm not asking that every student can write the equivalent of a novel. We don't do that in English either. In fact, I'm not even asking that they be able to write the equivalent of a five page essay. I'm asking that they have the experience of writing a little script to solve some problem. I would argue that is similar to asking that they know how to compose a few sentences like what kids do in early elementary school. In fact, there is a movement growing to have students doing this at the elementary school level, and the US is behind the curve in this area (see Code.org and http://neil.fraser.name/news/2013/03/16/).

Why do I think this is so important? There are several reasons. We are supposed to be preparing students to live in the 21st century. Most of our students already carry a computing device, in the form of a smart phone, with them more than they do books, yet they are completely incapable of creating any level of content on that device. They are literally marginalized by that inability.

In addition, programming is all about problem solving. Honestly, I think that the formalized thinking of programming is more important for students to learn today than even a foreign language. Both have cognitive advantages to those who learn them, but the way the world is moving, I believe that the thinking skills that go into programming are the more significant of the two.

Going further with the topic of problem solving, the reality is that more and more problems are becoming solvable only with the use of a computer. For the most part this is happening because the data sets involved in solving these problems have gotten to the point where you simply can't manipulate them by hand. This isn't just true in the sciences, big data sets are now the norm for social sciences and many humanities as well. The argument was raised that students can just use existing programs to solve those problems. To my mind, that's like saying that students don't need to know how to write because they can just copy and paste the ideas that other people have written. Also, just like the writing, I would argue that we want our students solving novel problems so eventually they want to say something that hasn't been said before. If that happens and they don't know how to write, they are stuck. Same thing applies to code. If you need to solve something and can't find existing programs for it, you either write it yourself or you are stuck. Knowing how to code gives you the advantage of at least being able to consider writing it yourself.

Once again, I'm definitely not arguing that everyone be a CS major. In fact, I don't even want these courses taught in CS. I think that CS will have to help other faculty with them, especially early on, but I think that this will be most effective if it is done in the context of students using computers to solve problems in other domains that they are truly interested in. I made the analogy to reading and writing above, but an analogy to math works just as well. We want every one of our students to know algebra. Why? Because there are many problems that are easy to solve if you know algebra and much harder if you don't. We don't want to teach algebra so that every student will be a math major. Math majors do many things that aren't even touched upon in algebra courses. In this situation, the algebra is a tool that is useful to people. As computing devices become more widespread and the data sets that are significant for problems in all fields grow, the significance of programming increases as well. Writing a script becomes just as essential a capability as writing a short letter or solving a little equation. At least that I how it seems to me. Comment with your own thoughts.

Addendum: Aaron Delwich pointed out how important it is that the computer is a universal machine. A printing press prints books, nothing else. It is specialized. One of my colleagues at the meeting also mentioned a car, saying he could argue that we should teach all students about internal combustion engines, but cars are also very special purpose. The computer is universal. It can do any operation you want with information. That is why they are used in every field to solve all kinds of problems and why learning about them is not the same as learning to operate a printing press or how an engine works.

Thursday, February 21, 2013

Are the Humanities Killing Themselves?

This blog post, as with many of the others I have written recently, focuses on the efforts of some to change the standard student workload at Trinity to 4 courses/semester each counting for 4 credits (a 4-4 load) instead of the current 5 courses of 3 credits. This proposal normally also has attached to it a change in teaching load so that faculty teach 3 courses one semester and 2 the next instead of 3 courses every semester [*].  This change will have a lot of implications, but one interesting point to note is that, if I paint with overly broad strokes, most of the support for this comes from the humanities and social sciences, while most of the opposition comes from the STEM and pre-professional departments [**]. Something I have discussed with others, and which I truly believe to be the case, is that the departments supporting this move, along with a proposed change to our common curriculum, do so at their own peril. I want to elaborate on this idea here in part to record it and perhaps to bring it forward for broader discussions.

The move to the 4-4, and the new curriculum proposal that will come with it have one inevitable consequence, students will take a smaller number of courses and will get less diversity in the departments they are exposed to. The 4-4 makes that first point unavoidable. The second point happens because our current breadth requirements would be impossible to maintain under the 4-4 and the new proposal, which I should point out I support, does not require students to take courses in as many different departments.

So why do I think that this should bother the faculty in the humanities? Well, to pick on one particular major, how many people enter college saying they want to major in Religion? Of course, Religion isn't alone. There are a number of majors that only get majors by having them take introductory courses and fall in love with the topic. Some are even in STEM. The Geoscience department comes to mind as an example. This alone should probably give those departments second thoughts, but I am sure they can easily say that it will improve their departments in other ways so it is worth it.

What I feel they ignore though is the changing national view on the role of higher education. More pressure is being put on the idea that students should major in something that will get them jobs. This goes along with the complaints that students are leaving college with too much debt and then they aren't able to find jobs. This is why we see proposed legislation that will force colleges to report earnings of graduates by major.

I am personally already feeling some of the fallout of the change in how students are picking majors. I have 35 students in my CS2 courses at Trinity. We haven't had that many students go on to the second semester in a decade. CS is one of the few areas where people hear about there being lots of jobs and not enough people to fill them these days. It might still be true that no one goes to college thinking they want to major in Geoscience, but if they look at the incomes associated with that major they can probably be convinced.

What about other departments like Religion and History? I expect they are going to take a hit from this in the next few years as more and more students enter college thinking about their earning potential. Even if the Wyden-Rubio legislation does not pass, they have access to things like the "What's it Worth?" report for Georgetown. They will also find things like this Forbes article entitled "The 10 Worst College Majors", which slams most humanities majors for high unemployment and low incomes. So why would these departments support changes that are going to likely reduce the number of students coming into their classrooms and hence their ability to attract majors? Obviously I don't have an answer to that because it makes no sense to me, but I want to dig a bit deeper to make it clear what could be at stake for these departments.

Let's pick the top two departments from the top of the What's it Worth salary survey and some comparison humanities departments and look at faculty counts.

Engineering Science - 9
Computer Science - 7
Art and Art History - 12
History - 11
Religion - 9

Right now the humanities departments have as many or more faculty than the majors that will inevitably be getting a lot more attention if students and parents really start looking at ROI on a college education. (I know that liberal arts are all about the additional benefits of being broadly educated, but I promise you that parents are not blind to the dollar signs when they are looking at colleges for their kids. As such, this can't be ignored no matter how good the arguments are that some things matter more than money.) So the move to the 4-4 and the new curriculum will contract the distribution requirement and pull students out of almost every department, making major counts more important. Then, if we really do get a push toward majors that lead to jobs it seems to me that a lot of the humanities departments might have a hard time filling their classrooms and justifying their current faculty counts.

Note that I'm not wishing this on them or saying this is a good thing. Quite the opposite. By opposing the 4-4, I'm pushing to keep students taking a broader distribution of courses and make it so that even if more students choose to major in the sciences, the humanities will retain reasonable enrollments. I'm writing this because I don't think most of the humanities faculty see it that way and I'm wondering what they expect to see happen with their total head count in the next five years if they pass the 4-4 and the new curriculum.

[*] This isn't really a drop in teaching load. The current system has faculty teaching a total of 18 credit hours each year. The altered system would have them teaching 20.

[**] This is an overly broad generalization. My guess is that this post will be read by at least one Communications professor who doesn't favor the proposal. It is also problematic for Music. In addition, I'm sure a few STEM faculty are supportive. However, in general this dividing line holds.

Wednesday, January 2, 2013

Loop Performance and Local Variables in Scala

This post was motivated by Local variables inside a loop and performance. I have to admit that the results of that post didn't really surprise me. For the code that they had written I felt like any reasonable compiler should have made the stack frame for the whole function big enough to hold those variables so that there was no additional work done for local declaration inside of a loop. What interested me though was whether the same would be true in Scala.

Why Scala Might Be Different
The for loop in Java is just a dressed up while loop. It is useful because it gives you places to put all the main components of a loop so that you are less likely to forget them. However, when you convert it to the assembly level (or bytecode level) it should have a conditional branch at the top and a non-conditional branch at the bottom with little additional overhead. In Scala however, the for loop is better described by the name "for comprehension". In a sense, there is no for loop in Scala. Instead, uses of for get translated to calls to higher order methods like map, flatMap, filter, and foreach. As an example, consider this for loop in Scala.

for (i <- 0 until runs) {
  val x = i % 12
  val y = i / 12 % 12
  val times = x * y
  counters(times) += 1
}

This gets translated to the following:

(0 until runs).foreach(i => {
  val x = i % 12
  val y = i / 12 % 12
  val times = x * y
  counters(times) += 1
}

This very simple example doesn't really show the power that is gained by this translation, but the capabilities of for comprehensions really do add a lot to Scala. Some of these features include simple data parallelism with parallel collections and concise syntax for Futures in the Akka framework. However, this greater power does come with some overhead in terms of performance. This change also makes it less clear to me if local variables in for loops would be significant.

Test Code
The following code shows how I modified the Java from Peter's blog post. The initial calls to the test functions are there to allow the JIT to go through the code before any timing is done. I also went a bit further and had each function call happen multiple times so that I could get a standard deviation in addition to average values. There are two functions using the for loop and two using the while loop.

object LocalVars {
  def main(args:Array[String]) {
    testInsideForLoop
    testOutsideForLoop
    testInsideWhileLoop
    testOutsideWhileLoop
    printResults("In for loop:",Array.fill(10000)(testInsideForLoop))
    printResults("Out of for loop:",Array.fill(10000)(testOutsideForLoop))
    printResults("In while loop:",Array.fill(10000)(testInsideWhileLoop))
    printResults("Out of while loop:",Array.fill(10000)(testOutsideWhileLoop))
  }

  def printResults(header:String,results:Array[Double]) {
    println(header)
    val average = results.sum/results.length
    printf("Average = %.3f ns\n", average)
    val aveSqr = results.map(x => x*x).sum/results.length
    printf("Standard dev = %.3f ns\n\n", math.sqrt(aveSqr-average*average))
  }

  def testInsideForLoop:Double = {
    val start = System.nanoTime()
    val counters = Array.fill(144)(0)
    val runs = 1000 * 1000
    for (i <- 0 until runs) {
      val x = i % 12
      val y = i / 12 % 12
      val times = x * y
      counters(times) += 1
    }
    (System.nanoTime() - start).toDouble / runs
  }

  def testOutsideForLoop:Double = {
    val start = System.nanoTime()
    val counters = Array.fill(144)(0)
    val runs = 1000 * 1000
    var x, y, times = 0
    for (i <- 0 until runs) {
      x = i % 12
      y = i / 12 % 12
      times = x * y
      counters(times) += 1
    }
    (System.nanoTime() - start).toDouble / runs
  }

  def testInsideWhileLoop:Double = {
    val start = System.nanoTime()
    val counters = Array.fill(144)(0)
    val runs = 1000 * 1000
    var i = 0
    while (i < runs) {
      val x = i % 12
      val y = i / 12 % 12
      val times = x * y
      counters(times) += 1
      i += 1
    }
    (System.nanoTime() - start).toDouble / runs
  }

  def testOutsideWhileLoop:Double = {
    val start = System.nanoTime()
    val counters = Array.fill(144)(0)
    val runs = 1000 * 1000
    var x, y, times, i = 0
    while (i < runs) {
      x = i % 12
      y = i / 12 % 12
      times = x * y
      counters(times) += 1
      i += 1
    }
    (System.nanoTime() - start).toDouble / runs
  }
}

Results
I compiled the above code using using Scala 2.10.0-RC5 with the -optimise option. When I ran it I got the following output.

In for loop:
Average = 6.073 ns
Standard dev = 0.448 ns

Out of for loop:
Average = 6.084 ns
Standard dev = 0.507 ns

In while loop:
Average = 4.670 ns
Standard dev = 0.322 ns

Out of while loop:
Average = 4.669 ns
Standard dev = 0.320 ns


It is clear that where you declare local variables doesn't matter at all as all variations are inside the error bars for the measurement. However, there is a reasonable performance penalty for using the for loop. The ScalaCL project provides one approach to getting around this. Since ScalaCL is not up to date with 2.10 I didn't test this out. Earlier testing under 2.8 showed me that it generally did bring the performance of for loops in line with while loops. I would love to see the ScalaCL project get more support both for this reason and to improve the OpenCL collections.

More Questions
I have two problems with what is done here. First, my Scala code is not at all Scala-like. Part of this is because Peter picked a problem that is best solved in a very imperative way. It would be interesting to pick a problem that also has a nice functional solution and then play with that a bit. This would also make it possible to try seeing how using parallel collections could be beneficial.

A more significant question was posed in a discussion on Google+ by one of my former students, Will Shepherd. This is the question of what happens with memory if the variables are a bit more complex. Here again, the chosen example code holds us back a bit as there doesn't seem to be much need for non-primitive variables here. However, the results could be extremely different if the variable were to hold an array or some type of mutable object.

Perhaps someone can suggest a problem that would make some sense in exploring these two avenues.

Conclusion
My take away message from Peter's original blog, which I think hold true here as well is that your best bet is to write good code first, then worry about performance as needed. Declaring variables locally is just a good idea. Limiting scope is remarkably helpful in preventing bugs. So that is how you should write your code. If you find that your code isn't fast enough once you have it working, then you explore options for making it faster. In the case of local declarations of primitive variables in loops, I think it is clear that there isn't any point in even trying that route. However, if you do decide to start exploring optimizations, you need to be careful and meticulous. Re-benchmark after each "optimization" because it is possible that you might make a change which leads to uglier, harder to maintain code without getting any speed benefit at all.

Sunday, November 25, 2012

The Fallacy of "Deep" Courses and Workloads

Background

This is back on the proposal that is being considered at Trinity to change student course loads to 4 courses per semester, each worth 4 credits (4-4) and the associated change in teaching load to five courses each year with 3 one semester and 2 the next (3-2). I am writing this blog post because I am finally getting fed up with statements that I keep hearing about how some courses simply require more time than others, especially time spent outside of class. There is also an associated aspect of this, where the same people who make these statements insinuate that this extra time is needed for their courses because they are too "deep" for a normal 3 credits.

Why I am Upset

Here is the problem, you don't hear these things coming from STEM faculty. You know, the people teaching the science and math courses that most students consider to be the hardest courses on campus. The majority of STEM faculty seem to be quite happy with how things are. The push for change seems to be coming largely from the humanities and social sciences.

I guess what really offends me is that these statements imply that because I am happy with my course counting for 3-credits that somehow my course is easier and less deep. I'm sorry, but I have had many students tell me that the courses I teach are the hardest ones they take during their entire time at Trinity. My courses also keep students very busy outside of the classroom. My guess is that most of the students in my courses will spend more time on my class than on any of the other courses they are taking. In fact, when students can't do that they tend to wind up withdrawing from my course.

My courses aren't time consuming because they are full of busy work either. They are time consuming because students have to wrap their heads around completely new ways of thinking, and they have to learn to break down problems to levels they have never done before. Then they are forced to apply those capabilities and they are forced to make things work. My courses aren't fluff. They are rigorous and challenging and it is really getting on my nerves how so many faculty seem to be saying that their courses are harder than mine and hence need to count for more credits.

This doesn't just apply to my courses either. Anyone who tells you that courses like E&M, Quantum Mechanics, or Complex Analysis don't require deep thinking or much time spent outside of class clearly has no idea what he/she is talking about. They have obviously not spent time trying to picture a vector field flowing through a Gauss pillbox.

If people really want to get some data on what departments have more challenging courses, and which ones require more time and effort both inside and outside of class, there is a publicly available data set for that called RateMyProfessors.com. They list ease as a criteria. If you scan through it for faculty with an ease rating of 2.5 or less, you will notice that STEM faculty are extremely over represented. (So is the English department.)

(Here is a coding assignment for any of my students reading this. Write a program to scrape data from RateMyProfessor.com. I'm most interested in department and ease for this topic, though it would be good to have names so that people who aren't current faculty can be removed.)

Enforcing Work

My gut feeling is that faculty who think they need students to take fewer courses and want students to have more time outside of class really just need to find better ways of enforcing work done outside of class. The idea that students are booked solid with academics when taking five 3-credit courses is absurd. Trinity students spend lots of time doing many things that aren't academic. Give them more time outside of class and they will use it for a variety of non-academic activities unless you can enforce that they use it doing the work for your class.

The fallacy that STEM courses somehow require less time outside of class is absurd. The reality is that STEM courses typically do a much better job of enforcing that students actually do what they are supposed to do outside of class. I can give my students assignments and exercises and if they don't take the time to learn the material, they will be completely incapable of doing those assignments. No, my students don't read everything I assign. However, they will read enough to be able to write the programs I ask them to do. (Honestly, many students would probably spend a little less time on my class if they would do the reading up front instead of wasting hours trying to code before they understand what they are doing.) I know this is more challenging for many non-STEM courses, but that doesn't mean it is impossible.

The bottom line, as I see it, is that changing the number of hours/credits for a course doesn't make students do more work, and making new policies based on the idea that it will is a great way to reduce the quality of a Trinity education. If faculty want students to do more work on their course, they need to be inventive and creative and find ways to enforce students doing the required work. That is the only way to make change happen.

Feedback

I'd love to hear back from anyone who reads this and is willing to say which courses they had in college that challenged them the most or kept them busy the most. I'd also love to hear why. This is especially true for Trinity students.

(Update: I would like to thank Laura Gibbs for pointing out the National Survey of Student Engagement in the Google+ discussion of this post. Ideally students should be spending 2 hours outside of classes for every hour inside of class. This survey shows that students spend between 12 and 18 hours total prepping for class. In other words, they aren't even close to the 2-hour mark. If faculty want students to work harder, the reality is that most students have time in their schedules. They just need to be forced to take the time.)

Aside: A Useful Technique

I'll close with a technique that I learned in grad school for Amer Diwan who taught a course on program analysis. This course was all about reading journal articles. I have used this approach to good effect in similar courses at Trinity. Make students show up to class with written questions on the reading. If you don't want to do questions, have them write a short paragraph instead. Base the in class discussion on the questions students hand to you when they first walk in. Have a portion of the semester grade come from the quality of what the students write for this. Call students out when what they provide sucks and shows that they didn't really put in the effort.

Saturday, October 20, 2012

Problems with the 4-4 Student Load

As I have mentioned previously, Trinity is considering changing from the current student load of ~5 courses each semester to a load of ~4 courses each semester. This alternate configuration is called a 4-4 student load as each student normally takes 4 courses, each of which is 4 hours of credit. A related proposal is to reduce the teaching load from the current 3-3, which each faculty member teaches three courses each semester, to a 3-2 teaching load where faculty alternate between 3 and 2 courses. In general I am opposed to both of these changes, but I have to admit that my opposition is based largely on thought experiments and imagined consequences instead of empirical data.

This weekend I got the chance to talk to someone who teaches at Southwestern University. They made the change from a 5-5 student load and 3-3 teaching load to 4-4 and 3-2 a few years ago. So this faculty member has direct experience with both of these systems. I wanted to record what we talked about and her perspective of that change here, because I felt that she had some very good insights.

Lack of Student Flexibility
The #1 problem that she described was something I hadn't even thought of, a lack of student flexibility in scheduling. In a 4-4 student load situation, students really need to take 4 courses each and every semester. The reason being that it isn't feasible for most students to go up to 5 courses when each one is four hours, and if you have more than one or two semesters with only three courses, you won't graduate on time.

All faculty know that occasionally students get in over their heads or sign up for courses they really aren't prepared to take. Under a 4-4 scheme, these students really can't drop those courses without pushing back their graduation. In the case where students choose to register for only 3 courses originally and take a light load, they have an even worse problem if it turns out that one course causes them problems because then dropping to two courses can cause problems related to full-time enrollment for the year. That leads to all types of financial difficulties for most students.

Under the category of lacking flexibility, Southwestern also runs into problems when it comes to transfer students and transfer credit. Given the challenges of enrolling students, transfers are potentially very important to many liberal arts schools. How do you count the 3-hour credits that most transfer students will come in with? Similarly, many Trinity students take summer courses away from Trinity and the same it true for Southwestern. We can't give students 4-hours of credit for a 3-hour summer course taken elsewhere. So we might check off a requirement for them, but they run into problems when it comes to total hours. Here again you can have students who fail to graduate on time because they don't have the right number of hours. With a 4-4 configuration you simply lose the flexibility for students to go slightly above the normal requirements to offset deficiencies.

Too Few Courses
Closely related to the problem of student enrollment flexibility is the problem of course offering flexibility. The faculty member I talked to noted that her department (a STEM department) was forced to reduce their major to 10 courses. This reduces the number of electives that students take as part of the major and how many electives can be offered. Not only are there fewer faculty teaching slots for electives, students don't take many so it is hard to get a critical mass of students to validate offering them.

An odd side effect of having majors cut down to 10 courses was that some departments bend the rule by hiding requirements in prerequisites. In particular she mentioned that the physics department, in order to get under the 10 course limit, doesn't explicitly list any math requirements. Instead, they have math courses as prerequisites on certain physics courses, making them implicit requirements. I know that Trinity highly frowns on implicit requirements, and the University Curriculum Committee typically rejects any such proposal. However, some fields truly do have a need to include more courses, especially when outside requirements are included.

Caps on majors or just the limits to courses could cause problems for things like theses as well. The CS department at Trinity does a 3-semester honors thesis track. There is no way we can do three semesters when students only take four courses each semester. This is definitely one of those situations where two, four hour courses are not even close to the equivalent of three, three hour courses.

The last problem presented by reduced course flexibility with the change made at Southwestern is in the inability to offer short seminars and the like on topics of interest. There modified system does not nicely support the equivalent of one and two hour seminars or independent studies. This can make it much harder to support undergraduate student research.

Courses Didn't Increase in Difficulty
The primary arguments for the 4-4 student load is that students are overburdened by having five courses each semester and that courses could be more rigorous if students only took four. I have always felt that this argument falls flat. Students spend a lot of time doing things outside of academics. If faculty members really want their students to dedicate more time to their course, they simply need to make the course harder and find ways to enforce that students really do the work. It might not be easy or even obvious how to do it, but that is what needs to be done. If faculty can't find ways to enforce students doing the work, moving to the 4-4 model isn't going to help.

Indeed, the Southwestern faculty member said that my fears match what has happened there. Few faculty have actually made their courses more rigorous. What is worse, because most of the courses went to 4-credits without going up to 4-hours, she feels that students are actually spending less time working on academics. Why? Because students now only have 12-hours in class. So when they look at their schedule they see even more "free time" and they tend to book it for things like jobs, sports, or other extra-curricular activities. Once they have done that, they truly don't have the time to complete extra rigour even if faculty members step up and make their courses more rigorous.

The reality is that you have to change that campus mentality toward courses and course work and that is more important than how many courses students take or how many hours they meet. Apparently Southwestern is experiencing most of what I see as the worst possibilities of moving to a 4-4 and virtually none of the benefits. However, because they went down to a 3-2 teaching load, faculty see a benefit so it will be nearly impossible to switch back.

Adjuncts and Conclusions
One last odd problem that Southwestern has run into is that challenge in hiring adjunct faculty. That can be a challenging process in many departments when asking them to teach a three credit course. Asking them to teach a four hour course makes it harder. If they are teaching a course that only meets three hours, but is supposed to have a harder workload, it is very unlikely that they will require the desired level of effort.

The general conclusion from this faculty member was that she couldn't find anything good to say about the 4-4 student load at Southwestern. Only the negatives of the change have been manifest in the implementation. The same is almost true of the 3-2 teaching load with the minor exception that there is some small benefit to having the freedom of picking when the 2-course semester is done. However, in practice Trinity does not appear to be extremely strict about making certain every faculty member teaches three courses every semester so this is not really a practical benefit.