Page Not Found
Sorry, but the page you were trying to view does not exist — perhaps you can try searching for it below.
A list of all the posts and pages found on the site. For you robots out there is an XML version available for digesting as well.
Sorry, but the page you were trying to view does not exist — perhaps you can try searching for it below.
I am currently an Assistant Professor at Colgate University. My research focus is in Computer Science Education Research (CER). I graduated with a PhD in Computer Science at Rutgers University in 2021.
Introducing Code Quality in the CS1 Classroom, ITICSE 2024 [Paper]
A synthesized model that promotes both procedural and conceptual knowledge dimensions in CS1, CEP 2024 [Paper] [Presentation Slides] [Materials]
This is a page not in the menu. You can use markdown in this page.
Published:
Alec Wydra, Judah Robbins Bernal and Yuliia Heleveria presented our posters at Colgate’s Summer Research Symposium.
Published:
Sarah Cryan and Greta Hoogstra presented our poster at Colgate’s Summer Research Symposium.
Published:
Kevin and Ahmed presented our poster at SIGCSE’23.
Published:
Matt, Mathelide, Ahmed and Kevin presented at the NY6 Undergraduate Research Conference hosted at Colgate University.
Published:
Students from Colgate University attended GHC’22.
Published:
In Intro to Computing II, I ran an intervention on value vs. reference semantics that leverages colored boxes and sticky notes to illustrate the behavior of the Java notional machine. Video with the intervention and research paper with the results to come …
Published:
My students in COSC 480, Intro to Cryptography, got to build 1-rotor Enigma machines on potato chip cans.
Published:
My student, Emma Pizer got to talk about her Summer 2022 Research experience with The Colgate Maroon News.
Published:
Mary Ring (left) and Emma Pizer (right) presented their poster at Colgate’s Summer Research Poster Session.
Published:
Students from COSC 102 - Introduction to Computing II taught by Prof. Fourquet, Prof. Lyboult and I presented their games. Click here for game demo.
IGD Workshop at Colgate (for faculty and staff) - teaches concrete strategies to dialogue on difficult topics such as those involving DEI issues.
Colgate Women in Computer Science (WiCS) - through mentoring, open hours, career advice, and discussions of women in the CS field, WiCS hopes to create a support system for each other and bring together all class years in the CS department.
At Rutgers University, my colleagues and I studied a dataset spanning over 3.5 academic years, looking at the gender gap, trends related to the gender gap, and how they impact retention in introductory courses.
Monica Babes-Vroman, Isabel Juniewicz, Bruno Lucarelli, Nicole Fox, Thu Nguyen, Andrew Tjang, Georgiana Haldeman, Ashni Mehta, and Risham Chokshi. 2017. Exploring Gender Diversity in CS at a Large Public R1 Research University. In Proceedings of the 2017 ACM SIGCSE Technical Symposium on Computer Science Education (SIGCSE ‘17). Association for Computing Machinery, New York, NY, USA, 51–56.
Download conference paper here
(* indicates undergraduate student author)
On January 5th, 2024, I presented the paper on the new syntesized pedagogical model I developed for CS1 in Python and CEP. See slides here
Published:
Common job descriptions for someone who writes code are programmer, software developer, or software engineer. They are all describing the same job. The variety in names hints at the similarities and differences between software engineering and other engineering. Engineering aims to build something that serves a function, a product, or an artifact.
Most engineering activities involve a design that is separately developed from the product. There are three inter-related main ways in which software engineering differs:
In fact, it’s more common to hear about the software process vs. the software product in software engineering than design vs. product.
Software Analysis and Testing are very closely related to Software Quality. There are many desirable software qualities in software engineering: correctness, reliability (relative correctness), robustness (reasonable behavior even in circumstances that were not anticipated in the requirements), performance, usability (ease of use), verifiability (we will cover testing in this course), security, maintainability, reusability, portability, understandability (although some applications are less clear than others the design and implementation should not further affect it), interoperability, productivity, timeliness, visibility (transparency of the process, amenable for external examination).
When addressing software quality it’s also useful to consider the different parties: users, developers, and managers because some of the software qualities are visible to the user (we call these external qualities) and some are only visible to the developers of the system (we call these internal qualities). A user wants a product to be reliable, efficient, and easy to use. The developer wants it to be verifiable, maintainable, portable, and extensible, the manager wants the process to be productive, predictable, and easy to control.
Furthermore, while the process is for the most part not visible to the user, the product has user-visible components such as executable code and user manual, and intermediate components (work products or artifacts) such as requirements, design documents, test data, etc. These intermediate components can also be visible to other types of users (other than the end-users).
We conclude that there is a high overlap between external and internal qualities, product and process qualities which makes it hard to standardize it. There are several software quality models that share the same essential aspects but differ in emphasis and organization.
Some general principles to achieve the software qualities discussed prior are:
Code style is connected to many desirable software qualities of code, including correctness. Let’s look at this code:
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown())
cruiseControl.logUnauthorizedAccessAttempt();
if (user.isAstronaut())
cruiseControl.grantAccess(user);
if (user.isCommander())
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
Note that the last line of code is not part of the body of the last if
statement and in fact, gets executed every time the method authorize
is invoked. For this particular application, this goes beyond correctness and presents a high security risk. The fix is to add curly braces around the body like so:
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown()){
cruiseControl.logUnauthorizedAccessAttempt();
}
if (user.isAstronaut()){
cruiseControl.grantAccess(user);
}
if (user.isCommander()){
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
}
One may also conclude that the three cases are mutually exclusive and combine them in an if-else-if
structure like so:
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown()){
cruiseControl.logUnauthorizedAccessAttempt();
}
else if (user.isAstronaut()){
cruiseControl.grantAccess(user);
}
else if (user.isCommander()){
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
}
However, note that there is an asymmetry in the code from the fact that we are mixing authorizing code with non-authorizing code. We can increase the understandability of our code by separating them out like so:
class BoardComputer {
CruiseControl cruiseControl;
void authorize(User user) {
Objects.requireNonNull(user);
if (user.isUnknown()) {
cruiseControl.logUnauthorizedAccessAttempt();
return;
}
if (user.isAstronaut()) {
cruiseControl.grantAccess(user);
} else if (user.isCommander()) {
cruiseControl.grantAccess(user);
cruiseControl.grantAdminAccess(user);
}
}
}
Published:
One of the examples from last class used an enum
structure:
private Result analyzeOrganic(Sample sample) {
if (microscope.isHumanoid(sample) == false) {
return Result.ALIEN;
} else {
return Result.HUMANOID;
}
}
An enumeration is a pre-defined set of values, for example:
public enum Result {
HUMANOID, INORGANIC, ALIEN
}
The advantage to using an enumeration is that when you declare a variable, a parameter or return type of an enumeration type then all the values (stored in the variable, passed to the parameter or returned) must be in the predefined set of the enumeration. For example, analyzeOrganic
can only return three values.
Additionally, you can add attributes and constructor to enumerations just like with classes likes so:
public enum Result {
HUMANOID(75),
INORGANIC(40),
ALIEN(100);
final int coolnessIndex;
Result(int newCI){
this.coolnessIndex = newCI;
}
}
Warm-up Problem: How can we improve the quality of this code snippet:
class CruiseControl {
private double targetSpeedKmh;
void setPreset(int speedPreset) {
if (speedPreset == 2) {
setTargetSpeedKmh(16944);
} else if (speedPreset == 1) {
setTargetSpeedKmh(7667);
} else if (speedPreset == 0) {
setTargetSpeedKmh(0);
}
}
void setTargetSpeedKmh(double speed) {
targetSpeedKmh = speed;
}
}
Numbers without an apparent meaning that steer the program are called magic numbers. We can dispel their magic and thus improve the quality of the code by making them constants:
class CruiseControl {
static final int STOP_PRESET = 0;
static final int PLANETARY_SPEED_PRESET = 1;
static final int CRUISE_SPEED_PRESET = 2;
static final double CRUISE_SPEED_KMH = 16944;
static final double PLANETARY_SPEED_KMH = 7667;
static final double STOP_SPEED_KMH = 0;
private double targetSpeedKmh;
void setPreset(int speedPreset) {
if (speedPreset == CRUISE_SPEED_PRESET) {
setTargetSpeedKmh(CRUISE_SPEED_KMH);
} else if (speedPreset == PLANETARY_SPEED_PRESET) {
setTargetSpeedKmh(PLANETARY_SPEED_KMH);
} else if (speedPreset == STOP_PRESET) {
setTargetSpeedKmh(STOP_SPEED_KMH);
}
}
void setTargetSpeedKmh(double speed) {
targetSpeedKmh = speed;
}
}
Can we do better?
Note that nothing restricts the user to call setPreset
with values other than the three values it checks for and the function terminates without error. We can make the semantics of this function more transperant for outside usage by using an enum
construct like so:
class CruiseControl {
private double targetSpeedKmh;
void setPreset(SpeedPreset speedPreset) {
Objects.requireNonNull(speedPreset);
setTargetSpeedKmh(speedPreset.speedKmh);
}
void setTargetSpeedKmh(double speedKmh) {
targetSpeedKmh = speedKmh;
}
}
enum SpeedPreset {
STOP(0), PLANETARY_SPEED(7667), CRUISE_SPEED(16944);
final double speedKmh;
SpeedPreset(double speedKmh) {
this.speedKmh = speedKmh;
}
}
Published:
Conventions are rules that are widely agreed upon by professionals. Used approapriately and consistently, they can help with the readability of the code.
Rule 1: Remove excessive comments for example:
class Inventory {
// Fields (we only have one)
List<Supply> supplies = new ArrayList<>(); // The list of supplies.
// Methods
int countContaminatedSupplies() {
// TODO: check if field is already initialized (not null)
int contaminatedCounter = 0; // the counter
// No supplies => no contamination
for (Supply supply : supplies) { // begin FOR
if (supply.isContaminated()) {
contaminatedCounter++; // increment counter!
} // End IF supply is contaminated
}// End FOR
// Returns the number of contaminated supplies.
return contaminatedCounter; // Handle with care!
}
} // End of Inventory class
Becomes:
class Inventory {
List<Supply> supplies = new ArrayList<>();
int countContaminatedSupplies() {
if (supplies == null || supplies.isEmpty()) {
// No supplies => no contamination
return 0;
}
int contaminatedCounter = 0;
for (Supply supply : supplies) {
if (supply.isContaminated()) {
contaminatedCounter++;
}
}
return contaminatedCounter;
}
}
Rule 2: Remove code in comments for example:
class LaunchChecklist {
List<String> checks = Arrays.asList(
"Cabin Leak",
// "Communication", // Do we actually want to talk to Houston?
"Engine",
"Hull",
// "Rover", // We won't need it, I think...
"OxygenTank"
//"Supplies"
);
Status prepareLaunch(Commander commander) {
for (String check : checks) {
boolean shouldAbortTakeoff = commander.isFailing(check);
if (shouldAbortTakeoff) {
//System.out.println("REASON FOR ABORT: " + item);
return Status.ABORT_TAKE_OFF;
}
}
return Status.READY_FOR_TAKE_OFF;
}
}
Becomes:
class LaunchChecklist {
List<String> checks = Arrays.asList(
"Cabin Leak",
"Engine",
"Hull",
"OxygenTank"
);
Status prepareLaunch(Commander commander) {
for (String check : checks) {
boolean shouldAbortTakeoff = commander.isFailing(check);
if (shouldAbortTakeoff) {
return Status.ABORT_TAKE_OFF;
}
}
return Status.READY_FOR_TAKE_OFF;
}
}
Rule 3: Replace comments with constants for example:
enum SmallDistanceUnit {
CENTIMETER,
INCH;
double getConversionRate(SmallDistanceUnit unit) {
if (this == unit) {
return 1; // identity conversion rate
}
if (this == CENTIMETER && unit == INCH) {
return 0.393701; // one centimeter in inch
} else {
return 2.54; // one inch in centimeters
}
}
}
Becomes:
enum SmallDistanceUnit {
CENTIMETER,
INCH;
static final double INCH_IN_CENTIMETERS = 2.54;
static final double CENTIMETER_IN_INCHES = 1 / INCH_IN_CENTIMETERS;
static final int IDENTITY = 1;
double getConversionRate(SmallDistanceUnit unit) {
if (this == unit) {
return IDENTITY;
}
if (this == CENTIMETER && unit == INCH) {
return CENTIMETER_IN_INCHES;
} else {
return INCH_IN_CENTIMETERS;
}
}
}
Rule 4: Replace comments with utility methods for example:
class FuelSystem {
List<Double> tanks = new ArrayList<>();
int getAverageTankFillingPercent() {
double sum = 0;
for (double tankFilling : tanks) {
sum += tankFilling;
}
double averageFuel = sum / tanks.size();
// round to integer percent
return Math.toIntExact(Math.round(averageFuel * 100));
}
}
Becomes:
class FuelSystem {
List<Double> tanks = new ArrayList<>();
int getAverageTankFillingPercent() {
double sum = 0;
for (double tankFilling : tanks) {
sum += tankFilling;
}
double averageFuel = sum / tanks.size();
return roundToIntegerPercent(averageFuel);
}
static int roundToIntegerPercent(double value) {
return Math.toIntExact(Math.round(value * 100));
}
}
Rule 5: Do document implementation decisions using a pattern like this:
/*
* In the context of [USE CASE],
* facing [CONCERN]
* we decided for [OPTION]
* to achieve [QUALITY],
* accepting [DOWNSIDE].
*/
For example:
class Inventory {
private List<Supply> list = new ArrayList<>();
void add(Supply supply) {
list.add(supply);
Collections.sort(list);
}
boolean isInStock(String name) {
// fast implementation
return Collections.binarySearch(list, new Supply(name)) != -1;
}
}
Becomes:
boolean isInStock(String name) {
/*
* In the context of checking availability of supplies by name,
* facing severe performance issues with >1000 supplies
* we decided to use the binary search algorithm
* to achieve item retrieval within 1 second,
* accepting that we must keep the supplies sorted.
*/
return Collections.binarySearch(list, new Supply(name)) != -1;
}
Rule 6: Use examples in your documentation for instance:
class Supply {
/**
* The code universally identifies a supply.
*
* It follows a strict format, beginning with an S (for supply), followed
* by a five digit inventory number. Next comes a backslash that
* separates the country code from the preceding inventory number. This
* country code must be exactly two capital letters standing for one of
* the participating nations (US, EU, RU, CN). After that follows a dot
* and the actual name of the supply in lowercase letters.
*/
static final Pattern CODE =
Pattern.compile("^S\\d{5}\\\\(US|EU|RU|CN)\\.[a-z]+$");
}
Becomes:
class Supply {
/**
* The expression universally identifies a supply code.
*
* Format: "S<inventory-number>\<COUNTRY-CODE>.<name>"
*
* Valid examples: "S12345\US.pasta", "S08342\CN.wrench",
* "S88888\EU.laptop", "S12233\RU.brush"
*
* Invalid examples:
* "R12345\RU.fuel" (Resource, not supply)
* "S1234\US.light" (Need five digits)
* "S01234\AI.coconut" (Wrong country code. Use US, EU, RU, or CN)
* " S88888\EU.laptop " (Trailing whitespaces)
*/
static final Pattern SUPPLY_CODE =
Pattern.compile("^S\\d{5}\\\\(US|EU|RU|CN)\\.[a-z]+$");
}
Published:
Published:
class Network {
ObjectInputStream inputStream;
InterCom interCom;
void listen() throws IOException, ClassNotFoundException {
while (true) {
Object signal = inputStream.readObject();
CrewMessage crewMessage = (CrewMessage) signal;
interCom.broadcast(crewMessage);
}
}
}
With this improvement becomes:
class Network {
ObjectInputStream inputStream;
InterCom interCom;
void listen() throws IOException, ClassNotFoundException {
while (true) {
Object signal = inputStream.readObject();
if (signal instanceof CrewMessage) {
CrewMessage crewMessage = (CrewMessage) signal;
interCom.broadcast(crewMessage);
}
}
}
}
class CruiseControl {
static final double SPEED_OF_LIGHT_KMH = 1079252850;
static final double SPEED_LIMIT = SPEED_OF_LIGHT_KMH;
private double targetSpeedKmh;
void setTargetSpeedKmh(double speedKmh) {
if (speedKmh < 0) {
throw new IllegalArgumentException();
} else if (speedKmh <= SPEED_LIMIT) {
targetSpeedKmh = speedKmh;
} else {
throw new IllegalArgumentException();
}
}
}
Becomes:
class CruiseControl {
static final double SPEED_OF_LIGHT_KMH = 1079252850;
static final double SPEED_LIMIT = SPEED_OF_LIGHT_KMH;
private double targetSpeedKmh;
void setTargetSpeedKmh(double speedKmh) {
if (speedKmh < 0 || speedKmh > SPEED_LIMIT) {
throw new IllegalArgumentException();
}
targetSpeedKmh = speedKmh;
}
}
class TransmissionParser {
static Transmission parse(String rawMessage) {
if (rawMessage != null
&& rawMessage.length() != Transmission.MESSAGE_LENGTH) {
throw new IllegalArgumentException("Bad message received!");
}
String rawId = rawMessage.substring(0, Transmission.ID_LENGTH);
String rawContent = rawMessage.substring(Transmission.ID_LENGTH);
try {
int id = Integer.parseInt(rawId);
String content = rawContent.trim();
return new Transmission(id, content);
} catch (Exception e) {
throw new IllegalArgumentException("Bad message received!");
}
}
}
The exception type in catch
is too general, we can first make it more specific:
class TransmissionParser {
static Transmission parse(String rawMessage) {
if (rawMessage != null &&
rawMessage.length() != Transmission.MESSAGE_LENGTH) {
throw new IllegalArgumentException("Bad message received!");
}
String rawId = rawMessage.substring(0, Transmission.ID_LENGTH);
String rawContent = rawMessage.substring(Transmission.ID_LENGTH);
try {
int id = Integer.parseInt(rawId);
String content = rawContent.trim();
return new Transmission(id, content);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Bad message received!");
}
}
}
We can communicate this information further using the message in the exception like so:
class TransmissionParser {
static Transmission parse(String rawMessage) {
if (rawMessage != null
&& rawMessage.length() != Transmission.MESSAGE_LENGTH) {
throw new IllegalArgumentException(
String.format("Expected %d, but got %d characters in '%s'",
Transmission.MESSAGE_LENGTH, rawMessage.length(),
rawMessage));
}
String rawId = rawMessage.substring(0, Transmission.ID_LENGTH);
String rawContent = rawMessage.substring(Transmission.ID_LENGTH);
try {
int id = Integer.parseInt(rawId);
String content = rawContent.trim();
return new Transmission(id, content);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("Expected number, but got '%s' in '%s'",
rawId, rawMessage));
}
}
}
You may also pass the cause chain to the exception like so:
class TransmissionParser {
static Transmission parse(String rawMessage) {
if (rawMessage != null
&& rawMessage.length() != Transmission.MESSAGE_LENGTH) {
throw new IllegalArgumentException(
String.format("Expected %d, but got %d characters in '%s'",
Transmission.MESSAGE_LENGTH, rawMessage.length(),
rawMessage));
}
String rawId = rawMessage.substring(0, Transmission.ID_LENGTH);
String rawContent = rawMessage.substring(Transmission.ID_LENGTH);
try {
int id = Integer.parseInt(rawId);
String content = rawContent.trim();
return new Transmission(id, content);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
String.format("Expected number, but got '%s' in '%s'",
rawId, rawMessage), e);
}
}
}
Published:
[Guide for scientific reporting]
[Colgate’s Guide for how to paraphrase] (pages 17-18)
Published:
Published:
[10-17-2024 Worksheet] [10-17-2024 Answers]
Published:
Published:
Published:
This is a description of your talk, which is a markdown files that can be all markdown-ified like any other post. Yay markdown!
Published:
This is a description of your tutorial, note the different field in type. This is a markdown files that can be all markdown-ified like any other post. Yay markdown!
Published:
This is a description of your talk, which is a markdown files that can be all markdown-ified like any other post. Yay markdown!
Published:
This is a description of your conference proceedings talk, note the different field in type. You can put anything in this field.